﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Form1.cs" company="">
//   
// </copyright>
// <summary>
//   The form 1.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

#undef viewdebug

namespace FrontalMethod
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Globalization;
    using System.IO;
    using System.Text.RegularExpressions;
    using System.Windows.Forms;

    using FrontalMethod.Java;

    using Triangulator;
    using Triangulator.Geometry;

    using Edge = Triangulator.Geometry.Edge;
    using Point = System.Drawing.Point;

    /// <summary>
    /// The form 1.
    /// </summary>
    public partial class Form1 : Form
    {
        /// <summary>
        /// The alloc color.
        /// </summary>
        private readonly Color AllocColor = Color.LightBlue; // Цвет выделения кнопок добавить/удалить узлы

        /// <summary>
        /// The axes color.
        /// </summary>
        private readonly Color AxesColor = Color.Wheat; // Цвет осей XOY

        /// <summary>
        /// The back add del color.
        /// </summary>
        private readonly Color BackAddDelColor = Color.FromName("AliceBlue");
                               // Цвет фона для кнопок добавления/удаления узлов

        /// <summary>
        /// The back ground color.
        /// </summary>
        private readonly Color BackGroundColor = Color.FromName("ControlLightLight"); // Цвет фона

        /// <summary>
        /// The bad angle color.
        /// </summary>
        private readonly Color BadAngleColor = Color.YellowGreen; // Цвет выделения треугольников с "плохими" углами

        /// <summary>
        /// The bad square color.
        /// </summary>
        private readonly Color BadSquareColor = Color.Yellow; // Цвет выделения треугольников с малой площадью

        /// <summary>
        /// The base div color.
        /// </summary>
        private readonly Color BaseDivColor = Color.Bisque; // Цвет для основных делений шкалы

        /// <summary>
        /// The base points color.
        /// </summary>
        private readonly Color BasePointsColor = Color.Red; // Цвет основных точек зон

        /// <summary>
        /// The circle centers.
        /// </summary>
        private readonly List<Point> CircleCenters = new List<Point>(1); // Координаты центров дуг

        /// <summary>
        /// The density function color.
        /// </summary>
        private readonly Color DensityFunctionColor = Color.DarkOrange; // Цвет точек задания функции плотности

        /// <summary>
        /// The density function font.
        /// </summary>
        private readonly Font DensityFunctionFont = new Font("Ariel", 12);
                              // Шрифт для вывода значений функции плотности

        /// <summary>
        /// The inter div color.
        /// </summary>
        private readonly Color InterDivColor = Color.Beige; // Цвет для промежуточных делений шкалы

        /// <summary>
        /// The inter points color.
        /// </summary>
        private readonly Color InterPointsColor = Color.DarkRed; // Цвет промежуточных точек зон

        /// <summary>
        /// The rounding points.
        /// </summary>
        private readonly List<Point[]> RoundingPoints = new List<Point[]>(1); // Точки, лежащие на дуге

        /// <summary>
        /// The triangle num font.
        /// </summary>
        private readonly Font TriangleNumFont = new Font("Ariel", 9); // Шрифт для вывода номеров треугольников

        /// <summary>
        /// The zone coord color.
        /// </summary>
        private readonly Color ZoneCoordColor = Color.Blue; // Цвет для вывода координат узлов зон

        /// <summary>
        /// The zone coord font.
        /// </summary>
        private readonly Font ZoneCoordFont = new Font("Ariel", 10); // Шрифт для вывода координат узлов зон

        /// <summary>
        /// The zone line color.
        /// </summary>
        private readonly Color ZoneLineColor = Color.Black; // Цвет линий сетки

        /// <summary>
        /// The zone point num color.
        /// </summary>
        private readonly Color ZonePointNumColor = Color.Magenta; // Цвет для вывода номеров узлов зон

        /// <summary>
        /// The zones font.
        /// </summary>
        private readonly Font ZonesFont = new Font("Times New Roman", 25); // Шрифт для обозначения номеров зон

        /// <summary>
        /// The mathematic.
        /// </summary>
        private readonly Mathematics mathematic = new Mathematics();

        /// <summary>
        /// The provider.
        /// </summary>
        private readonly NumberFormatInfo provider = new NumberFormatInfo();

        /// <summary>
        /// The time start.
        /// </summary>
        private readonly Stopwatch timeStart = new Stopwatch();

        /// <summary>
        /// The all elem.
        /// </summary>
        private List<Point[]> AllElem; // Список всех КЭ

        /// <summary>
        /// The all points.
        /// </summary>
        private List<Point>[] AllPoints; // Список координат всех точек для каждой зоны

        /// <summary>
        /// The all points array.
        /// </summary>
        private List<Point> AllPointsArray; // Список координат всех узлов

        /// <summary>
        /// The all points num.
        /// </summary>
        private List<int> AllPointsNum; // Список номеров всех узлов

        /// <summary>
        /// The avg density function.
        /// </summary>
        private double AvgDensityFunction = 3; // Значение функции плотности по умолчанию

        /// <summary>
        /// The axes pen.
        /// </summary>
        private Pen AxesPen; // Карандаш для осей XOY

        /// <summary>
        /// The back ground brush.
        /// </summary>
        private SolidBrush BackGroundBrush; // Кисть цвета фона

        /// <summary>
        /// The bad angle.
        /// </summary>
        private List<double[]>[] BadAngle; // Углы "плохих" треугольников

        /// <summary>
        /// The bad angle brush.
        /// </summary>
        private SolidBrush BadAngleBrush; // Кисть выделения треугольников с "плохими" углами

        /// <summary>
        /// The bad angle num.
        /// </summary>
        private List<int>[] BadAngleNum; // Номера "плохих" треугольников с углами, выходящими за рамки допустимых

        /// <summary>
        /// The bad square brush.
        /// </summary>
        private SolidBrush BadSquareBrush; // Кисть выделения треугольников с малой площадью

        /// <summary>
        /// The bad triangles num.
        /// </summary>
        private List<int>[] BadTrianglesNum; // Номера "плохих" треугольников с малыми площадями

        /// <summary>
        /// The base div pen.
        /// </summary>
        private Pen BaseDivPen; // Карандаш для основных делений шкалы

        /// <summary>
        /// The base points brush.
        /// </summary>
        private SolidBrush BasePointsBrush; // Кисть основных точек зон

        /// <summary>
        /// The density function brush.
        /// </summary>
        private SolidBrush DensityFunctionBrush; // Кисть выделения точек задания функции плотности

        /// <summary>
        /// The density points.
        /// </summary>
        private List<Point>[] DensityPoints;
                              // Список точек функции плотности, заданных для каждой зоны\\\\\\\\\\\\\\\\

        /// <summary>
        /// The density values.
        /// </summary>
        private List<double>[] DensityValues;
                               // Список значений функции плотности, заданных для каждой зоны\\\\\\\\\\\\\

        /// <summary>
        /// The external front.
        /// </summary>
        private Point[][] ExternalFront; // Фронт, меняющийся во время построения сетки КЭ

        /// <summary>
        /// The front.
        /// </summary>
        private Point[][] Front; // Фронт (не изменяющийся)

        /// <summary>
        /// The front zone.
        /// </summary>
        private GraphicsPath FrontZone = new GraphicsPath(); // Фигура, описывающая фронт

        /// <summary>
        /// The inside pen.
        /// </summary>
        private Pen InsidePen; // Карандаш для внутреннего разбиения зон

        /// <summary>
        /// The inside points.
        /// </summary>
        private List<Point[]>[] InsidePoints; // Список координат всех треугольников++++++++++++++

        /// <summary>
        /// The inter div pen.
        /// </summary>
        private Pen InterDivPen; // Карандаш для промежуточных делений шкалы

        /// <summary>
        /// The inter points brush.
        /// </summary>
        private SolidBrush InterPointsBrush; // Кисть промежуточных точек зон

        /// <summary>
        /// The max allow angle.
        /// </summary>
        private double MaxAllowAngle = 175; // Максимальный допустимый угол

        /// <summary>
        /// The mesh step.
        /// </summary>
        private double MeshStep = 10; // Шаг разбиения зон

        /// <summary>
        /// The min allow angle.
        /// </summary>
        private double MinAllowAngle = 5; // Минимальный допустимый угол

        /// <summary>
        /// The min allow square.
        /// </summary>
        private double MinAllowSquare = 10; // Минимальная допустимая площадь треугольника  

        /// <summary>
        /// The min angle.
        /// </summary>
        private double MinAngle; // Минимальный угол КЭ в сетке

        /// <summary>
        /// The min square.
        /// </summary>
        private double MinSquare; // Минимальная площадь КЭ в сетке

        /// <summary>
        /// The temp front.
        /// </summary>
        private Point[] TempFront; // Вспомогательный фронт

        /// <summary>
        /// The triangle num.
        /// </summary>
        private int[][] TriangleNum; // Массив номеров КЭ++++++++++++++++++++++++++

        /// <summary>
        /// The zone coord brush.
        /// </summary>
        private SolidBrush ZoneCoordBrush; // Кисть для вывода координат узлов зон

        /// <summary>
        /// The zone pen.
        /// </summary>
        private Pen ZonePen; // Карандаш для зон

        /// <summary>
        /// The zone point num brush.
        /// </summary>
        private SolidBrush ZonePointNumBrush; // Кисть для вывода номеров узлов зон

        /// <summary>
        /// The zone point num font.
        /// </summary>
        private Font ZonePointNumFont = new Font("Ariel", 12); // Шрифт для вывода номеров узлов зон

        /// <summary>
        /// The zones points.
        /// </summary>
        private Point[][] ZonesPoints; // Точки зон*******************************

        /// <summary>
        /// The zones points num.
        /// </summary>
        private int[][] ZonesPointsNum; // Массив номеров узлов зон***********************

        /// <summary>
        /// The b add.
        /// </summary>
        private bool bAdd; // Признаки добавления/удаления узлов

        /// <summary>
        /// The b allocation.
        /// </summary>
        private bool bAllocation; // Признак выделения точки

        /// <summary>
        /// The b delete.
        /// </summary>
        private bool bDelete; // Признаки добавления/удаления узлов

        /// <summary>
        /// The b density function.
        /// </summary>
        private bool bDensityFunction; // Признак режима задания функции плотности

        /// <summary>
        /// The b draw mesh.
        /// </summary>
        private bool bDrawMesh; // Признак рисования сетки

        /// <summary>
        /// The b draw triangle num.
        /// </summary>
        private bool bDrawTriangleNum; // Признак вывода номеров треугольников

        /// <summary>
        /// The b draw zone coord.
        /// </summary>
        private bool bDrawZoneCoord; // Признак вывода координат узлов зон

        /// <summary>
        /// The b draw zone point num.
        /// </summary>
        private bool bDrawZonePointNum; // Признак вывода номеров узлов зон

        /// <summary>
        /// The b error.
        /// </summary>
        private bool bError; // Признак наличия ошибки

        /// <summary>
        /// The b old point.
        /// </summary>
        private bool bOldPoint; // Признак изменеия функции плотности уже в построенной точке

        /// <summary>
        /// The b show bed triangle.
        /// </summary>
        private bool bShowBedTriangle; // Признак выделения "плохих" треугольников

        /// <summary>
        /// The b show density func.
        /// </summary>
        private bool bShowDensityFunc; // Признак отображения значений функции плотности

        /// <summary>
        /// The c points in zone.
        /// </summary>
        public int cPointsInZone = 8; // Количество узлов в зоне

        /// <summary>
        /// The c zone count.
        /// </summary>
        public int cZoneCount; // Количество зон

        /// <summary>
        /// The cur density func.
        /// </summary>
        private Point curDensityFunc; // Текущая точка задания функции плотности

        /// <summary>
        /// The cur zone density.
        /// </summary>
        private int curZoneDensity = -1; // Текущая зона, где задаётся функция плотности

        /// <summary>
        /// The eee.
        /// </summary>
        private Graphics eee; // Область построения

        /// <summary>
        /// The err.
        /// </summary>
        private ErrorMessage err; // Форма вывода сообщения об ошибке

        /// <summary>
        /// The f inter point size.
        /// </summary>
        private float fInterPointSize = 3; // Размер промежуточных точек

        /// <summary>
        /// The f miter angle.
        /// </summary>
        private float fMiterAngle = 90; // Угол выравнивания

        /// <summary>
        /// The f point size.
        /// </summary>
        private float fPointSize = 7; // Размер основных точек

        /// <summary>
        /// The f rounding radius.
        /// </summary>
        private float fRoundingRadius; // Радиус скругления

        /// <summary>
        /// The i elem count.
        /// </summary>
        private int iElemCount; // Количество КЭ

        /// <summary>
        /// The i mesh criterion.
        /// </summary>
        private int iMeshCriterion; // Критерий построения сетки 

        /// <summary>
        /// The i node count.
        /// </summary>
        private int iNodeCount; // Количество узлов

        /// <summary>
        /// The i offset xoy.
        /// </summary>
        private int iOffsetXOY = 10; // Смещение точки начала координат

        /// <summary>
        /// The i old point.
        /// </summary>
        private int iOldPoint = -1; // Номер точки, в которой меняется функция плотности

        /// <summary>
        /// The i point.
        /// </summary>
        private int iPoint; // Вспомогательные переменные (счетчик зон и точек в зоне для демонстрации)

        /// <summary>
        /// The i time delay.
        /// </summary>
        private int iTimeDelay = 20; // Временная задержка для демонстрационного построения сетки КЭ

        /// <summary>
        /// The i timer 3.
        /// </summary>
        private int iTimer3;

        /// <summary>
        /// The i zone.
        /// </summary>
        private int iZone; // Вспомогательные переменные (счетчик зон и точек в зоне для демонстрации)

        /// <summary>
        /// The i zone min angle.
        /// </summary>
        private int iZoneMinAngle; // Номер зоны с минимальным углом

        /// <summary>
        /// The i zone min square.
        /// </summary>
        private int iZoneMinSquare; // Номер зоны с минимальной площадью КЭ

        /// <summary>
        /// The multiplier.
        /// </summary>
        private int multiplier = 5; // Множитель, необходимый для корректного отображения пластины

        /// <summary>
        /// The p allocation.
        /// </summary>
        private Point pAllocation; // Выделяемая точка

        /// <summary>
        /// The plate height.
        /// </summary>
        private int plateHeight; // Ширина, высота пластины

        /// <summary>
        /// The plate width.
        /// </summary>
        private int plateWidth; // Ширина, высота пластины

        /// <summary>
        /// The sr.
        /// </summary>
        private StreamReader sr; // Класс чтения

        /// <summary>
        /// The sts.
        /// </summary>
        private Settings sts; // Форма настроек

        /// <summary>
        /// The sw.
        /// </summary>
        private StreamWriter sw; // Класс записи

        /// <summary>
        /// The tstpt.
        /// </summary>
        private TestPlate tstpt; // Форма оценки сетки

        /// <summary>
        /// The tstres.
        /// </summary>
        private TestResult tstres; // Форма результатов тестирования сетки

        /// <summary>
        /// The tt point.
        /// </summary>
        private Point ttPoint; // Точки(текущая и предыдущая) для вывода ToolTip

        /// <summary>
        /// The tt pre.
        /// </summary>
        private Point ttPre; // Точки(текущая и предыдущая) для вывода ToolTip

        /// <summary>
        /// Initializes a new instance of the <see cref="Form1"/> class.
        /// </summary>
        public Form1()
        {
            this.Width = Screen.PrimaryScreen.Bounds.Width;
            this.Height = Screen.PrimaryScreen.Bounds.Height;
            this.InitColors(true);
            this.InitializeComponent();
        }

        /// <summary>
        /// The read input file.
        /// </summary>
        private void ReadInputFile()
        {
            // Чтение файла исходных данных
            this.sr = File.OpenText("data");
            Match match;

            double fff; // Вспомогательная переменная
            string IOline;
            string pattern1 = @"(?<width>[0-9]+\.[0-9]*).*(WIDTH)";
            string pattern2 = @"(?<height>[0-9]+\.[0-9]*).*(HEIGHT)";
            string pattern3 = @"(?<radius>[0-9]+\.[0-9]*).*DR";

            while ((IOline = this.sr.ReadLine()) != null)
            {
                match = Regex.Match(IOline, pattern1);

                if (match.Success)
                {
                    fff = Convert.ToSingle(match.Groups["width"].Value, this.provider);
                    this.plateWidth = Convert.ToInt32(Math.Round(fff)); // Ширина пластины
                }

                match = Regex.Match(IOline, pattern2);
                if (match.Success)
                {
                    fff = Convert.ToSingle(match.Groups["height"].Value, this.provider);
                    this.plateHeight = Convert.ToInt32(Math.Round(fff)); // Длина пластины
                }

                match = Regex.Match(IOline, pattern3);
                if (match.Success)
                {
                    fff = Convert.ToSingle(match.Groups["radius"].Value, this.provider);
                    this.fRoundingRadius = Convert.ToInt32(Math.Round(fff)); // Радиус скругления
                    break;
                }
            }

            this.sr.Close();

            // Определение величины множителя
            if ((1.0 * this.plateWidth / this.plateHeight) <= 1.2)
            {
                this.multiplier = (int)Math.Round(0.82 * Screen.PrimaryScreen.Bounds.Height / this.plateHeight);
            }
            else
            {
                this.multiplier = (int)Math.Round(0.75 * Screen.PrimaryScreen.Bounds.Width / this.plateWidth);
            }

            this.fRoundingRadius = this.fRoundingRadius * this.multiplier;
            this.iOffsetXOY = 3 * this.multiplier; // Отступ от левого нижнего края

            this.sr = File.OpenText("form_xy");
            IOline = this.sr.ReadLine();
            this.cZoneCount = Convert.ToInt32(IOline); // Количество зон
            this.ZonesPoints = new Point[this.cZoneCount][];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.ZonesPoints[i] = new Point[this.cPointsInZone];
            }

            this.ZonesPointsNum = new int[this.cZoneCount][];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.ZonesPointsNum[i] = new int[this.cPointsInZone];
            }

            IOline = this.sr.ReadLine();
            int Nzone = 0, Npoint = 0; // Счёт зон и точек в зонах
            for (int j = 0; j < this.cZoneCount * this.cPointsInZone; j++)
            {
                IOline = this.sr.ReadLine();
                this.ZonesPointsNum[Nzone][Npoint] = Convert.ToInt32(IOline);
                IOline = this.sr.ReadLine();
                fff = Convert.ToSingle(IOline, this.provider);
                this.ZonesPoints[Nzone][Npoint].X = (int)Math.Round(fff * this.multiplier);
                IOline = this.sr.ReadLine();
                fff = Convert.ToSingle(IOline, this.provider);
                this.ZonesPoints[Nzone][Npoint].Y = (int)Math.Round(fff * this.multiplier);
                if (Npoint == this.cPointsInZone - 1)
                {
                    Npoint = 0;
                    Nzone++;
                }
                else
                {
                    Npoint++;
                }
            }

            this.sr.Close();
        }

        /// <summary>
        /// The write ini file.
        /// </summary>
        private void WriteIniFile()
        {
            // Запись файла настроек
            this.sw = File.CreateText(Application.StartupPath + '\\' + "FrontalMethod.ini");
            this.sw.WriteLine("[General]");
            this.sw.WriteLine("Subinterval = " + Math.Round(this.MeshStep / this.multiplier));
            this.sw.WriteLine("Points in zone = " + this.cPointsInZone);
            this.sw.WriteLine("MinAllowAngle = " + this.MinAllowAngle);
            this.sw.WriteLine("MaxAllowAngle = " + this.MaxAllowAngle);
            this.sw.WriteLine("MinAllowSquare = " + this.MinAllowSquare);
            this.sw.WriteLine("MiterAngle = " + this.fMiterAngle);
            this.sw.WriteLine("MeshCriterion = " + this.iMeshCriterion);
            this.sw.WriteLine("TimeDelay = " + this.iTimeDelay);
            this.sw.WriteLine("AvgDensityFunction = " + this.AvgDensityFunction);
            this.sw.Close();
        }

        /// <summary>
        /// Запись выходного файла.
        /// </summary>
        private void CreateOutFile()
        {
            // Формируем список всех узлов и их номеров
            int NodeNum = 0;
            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.AllPoints[j].Count; i++)
                {
                    if (this.FindIndexInList(this.AllPointsArray, this.AllPoints[j][i]) == -1)
                    {
                        NodeNum++;
                        this.AllPointsArray.Add(this.AllPoints[j][i]);
                        this.AllPointsNum.Add(NodeNum);
                    }
                }
            }

            this.iNodeCount = this.AllPointsArray.Count; // Количество узлов
            this.iElemCount = 0; // Количество КЭ
            for (int j = 0; j < this.cZoneCount; j++)
            {
                this.iElemCount += this.InsidePoints[j].Count;
            }

            // Формируем список всех КЭ
            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.InsidePoints[j].Count; i++)
                {
                    this.AllElem.Add(this.InsidePoints[j][i]);
                }
            }

            this.sw = File.CreateText("nodes.ftm");
            this.sw.WriteLine(string.Empty);
            this.sw.WriteLine(this.iNodeCount + "  Количество узлов");
            this.sw.WriteLine(this.iElemCount + "  Количество элементов");
            this.sw.WriteLine(string.Empty);
            this.sw.WriteLine("Координаты узлов");

#warning have to use this number format to write in outfile
#warning AllPointsArray
#warning AllPointsNum
#warning AllElem
            var numInfo = new NumberFormatInfo();
            numInfo.NumberDecimalSeparator = ".";

            // Выводим координаты всех узлов
            for (int j = 0; j < this.AllPointsArray.Count; j++)
            {
                string pointNumber = this.AllPointsNum[j].ToString();
                string pointCoordinateX = Math.Round(1.0 * this.AllPointsArray[j].X / this.multiplier, 2).ToString();
                string pointCoordinateY = Math.Round(1.0 * this.AllPointsArray[j].Y / this.multiplier, 2).ToString();
                this.sw.WriteLine(pointNumber + '\t' + pointCoordinateX + '\t' + pointCoordinateY);
            }

            this.sw.WriteLine(string.Empty);
            this.sw.WriteLine("Номера узлов, составляющие КЭ");
            for (int j = 0; j < this.iElemCount; j++)
            {
                this.sw.WriteLine(
                    (j + 1).ToString() + '\t' + (this.FindIndexInList(this.AllPointsArray, this.AllElem[j][0]) + 1) +
                    '\t' + (this.FindIndexInList(this.AllPointsArray, this.AllElem[j][1]) + 1) + '\t' +
                    (this.FindIndexInList(this.AllPointsArray, this.AllElem[j][2]) + 1));
            }

            this.sw.Close();
        }

        /// <summary>
        /// Функция чтения из ini-файла исходных данных 
        /// </summary>
        private void Init()
        {
            string IOline;

            this.sr = File.OpenText(Application.StartupPath + '\\' + "FrontalMethod.ini");
            string pattern1 = @"Subinterval = (?<subinterval>[0-9]+\.?[0-9]*)";
            string pattern3 = @"Points in zone = (?<zonelen>[0-9]+)";
            string pattern2 = @"MinAllowAngle = (?<minangle>[0-9]+\.?[0-9]*)";
            string pattern4 = @"MaxAllowAngle = (?<maxangle>[0-9]+\.?[0-9]*)";
            string pattern5 = @"MinAllowSquare = (?<minsquare>[0-9]+\.?[0-9]*)";
            string pattern6 = @"MiterAngle = (?<miterangle>[0-9]+\.?[0-9]*)";
            string pattern7 = @"MeshCriterion = (?<meshcriterion>[0-9]+)";
            string pattern8 = @"TimeDelay = (?<timedelay>[0-9]+)";
            string pattern9 = @"AvgDensityFunction = (?<avgfunc>[0-9]+\.?[0-9]*)";

            Match match;

            while ((IOline = this.sr.ReadLine()) != null)
            {
                match = Regex.Match(IOline, pattern1);
                if (match.Success)
                {
                    this.textBoxStepSize.Text = match.Groups["subinterval"].Value;
                    this.MeshStep = Convert.ToSingle(this.textBoxStepSize.Text, this.provider);
                }

                match = Regex.Match(IOline, pattern3);
                if (match.Success)
                {
                    this.cPointsInZone = Convert.ToInt32(match.Groups["zonelen"].Value);
                }

                match = Regex.Match(IOline, pattern2);
                if (match.Success)
                {
                    this.tstpt.numericUpDown1.Value = Convert.ToInt32(match.Groups["minangle"].Value, this.provider);
                    this.MinAllowAngle = Convert.ToSingle(this.tstpt.numericUpDown1.Value, this.provider);
                }

                match = Regex.Match(IOline, pattern4);
                if (match.Success)
                {
                    this.tstpt.numericUpDown2.Value = Convert.ToInt32(match.Groups["maxangle"].Value, this.provider);
                    this.MaxAllowAngle = Convert.ToSingle(this.tstpt.numericUpDown2.Value, this.provider);
                }

                match = Regex.Match(IOline, pattern5);
                if (match.Success)
                {
                    this.tstpt.textBox3.Text = match.Groups["minsquare"].Value;
                    this.MinAllowSquare = Convert.ToSingle(this.tstpt.textBox3.Text, this.provider);
                }

                match = Regex.Match(IOline, pattern6);
                if (match.Success)
                {
                    this.sts.textBox1.Text = match.Groups["miterangle"].Value;
                    this.fMiterAngle = Convert.ToSingle(this.sts.textBox1.Text, this.provider);
                }

                match = Regex.Match(IOline, pattern7);
                if (match.Success)
                {
                    this.iMeshCriterion = Convert.ToInt32(match.Groups["meshcriterion"].Value);
                    switch (this.iMeshCriterion)
                    {
                            // Критерий построения сетки КЭ
                        case 0:
                            {
                                this.sts.radioButton1.Checked = true;
                                this.sts.radioButton2.Checked = false;
                                this.sts.radioButton3.Checked = false;
                                this.sts.radioButton4.Checked = false;
                                this.sts.radioButton5.Checked = false;
                            }

                            break;
                        case 1:
                            {
                                this.sts.radioButton1.Checked = false;
                                this.sts.radioButton2.Checked = true;
                                this.sts.radioButton3.Checked = false;
                                this.sts.radioButton4.Checked = false;
                                this.sts.radioButton5.Checked = false;
                            }

                            break;
                        case 2:
                            {
                                this.sts.radioButton1.Checked = false;
                                this.sts.radioButton2.Checked = false;
                                this.sts.radioButton3.Checked = true;
                                this.sts.radioButton4.Checked = false;
                                this.sts.radioButton5.Checked = false;
                            }

                            break;
                        case 3:
                            {
                                this.sts.radioButton1.Checked = false;
                                this.sts.radioButton2.Checked = false;
                                this.sts.radioButton3.Checked = false;
                                this.sts.radioButton4.Checked = true;
                                this.sts.radioButton5.Checked = false;
                            }

                            break;
                        case 4:
                            {
                                this.sts.radioButton1.Checked = false;
                                this.sts.radioButton2.Checked = false;
                                this.sts.radioButton3.Checked = false;
                                this.sts.radioButton4.Checked = false;
                                this.sts.radioButton5.Checked = true;
                            }

                            break;
                    }
                }

                match = Regex.Match(IOline, pattern8);
                if (match.Success)
                {
                    this.iTimeDelay = Convert.ToInt32(match.Groups["timedelay"].Value);
                    this.hScrollBarSpeed.Value = this.iTimeDelay;
                }

                match = Regex.Match(IOline, pattern9);
                if (match.Success)
                {
                    this.AvgDensityFunction = Convert.ToSingle(match.Groups["avgfunc"].Value, this.provider);
                    this.sts.textBox2.Text = this.AvgDensityFunction.ToString();
                }
            }

            this.sr.Close();

            this.ReadInputFile(); // Чтение файла входных данных

            this.Front = new Point[this.cZoneCount][];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            // --------------------- Найдём все точки, лежащие на дуге  --------------------------
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    // И для каждой точки
                    Point pc1, pc2, pc3, pO;
                    if (i == 0)
                    {
                        pc1 = this.ZonesPoints[j][this.cPointsInZone - 1];
                        pc2 = this.ZonesPoints[j][0];
                        pc3 = this.ZonesPoints[j][1];
                    }
                    else if (i < this.cPointsInZone - 2)
                    {
                        pc1 = this.ZonesPoints[j][i - 1];
                        pc2 = this.ZonesPoints[j][i];
                        pc3 = this.ZonesPoints[j][i + 1];
                    }
                    else if (i == this.cPointsInZone - 2)
                    {
                        pc1 = this.ZonesPoints[j][i];
                        pc2 = this.ZonesPoints[j][i + 1];
                        pc3 = this.ZonesPoints[j][0];
                    }
                    else
                    {
                        pc1 = this.ZonesPoints[j][i];
                        pc2 = this.ZonesPoints[j][0];
                        pc3 = this.ZonesPoints[j][1];
                    }

                    pO = this.mathematic.IsCircle(pc1, pc2, pc3, this.fRoundingRadius, this.multiplier);
                        
                        // Находим координаты центра окружности
                    if (pO.X > -1000)
                    {
                        // Если точки лежат на дуге, добавляем их к списку
                        pO.X = (int)(Math.Round((double)pO.X / this.multiplier) * this.multiplier);
                        pO.Y = (int)(Math.Round((double)pO.Y / this.multiplier) * this.multiplier);
                        var ppp = new Point[3];
                        ppp[0] = pc1;
                        ppp[1] = pc2;
                        ppp[2] = pc3;
                        this.RoundingPoints.Add(ppp); // Точки, лежащие на окружностях
                        this.CircleCenters.Add(pO); // Точки центра окружностей
                    }
                }
            }

            this.BadAngleNum = new List<int>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadAngleNum[i] = new List<int>(1);
            }

            this.BadTrianglesNum = new List<int>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadTrianglesNum[i] = new List<int>(1);
            }

            this.BadAngle = new List<double[]>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadAngle[i] = new List<double[]>(1);
            }
        }

        /// <summary>
        /// The regularization.
        /// </summary>
        private void Regularization()
        {
            // Регуляризация
            GraphicsPath gp; // Текущая зона
            List<Point> pl; // список точек, связанных с выбранной
            double X = 0, Y = 0; // новые координаты точки
            var p = new Point(); // новая точка
            for (int j = 0; j < this.cZoneCount; j++)
            {
                gp = new GraphicsPath();
                gp.StartFigure();
                gp.AddLines(this.ZonesPoints[j]);
                gp.CloseFigure();
                for (int i = 0; i < this.AllPoints[j].Count; i++)
                {
                    if (gp.IsVisible(this.AllPoints[j][i]) &&
                        (this.FindIndexInArray(this.Front[j], this.AllPoints[j][i]) == -1))
                    {
                        // Если точка находится внутри зоны
                        pl = new List<Point>(1);
                        for (int k = 0; k < this.InsidePoints[j].Count; k++)
                        {
                            // Ищем все точки, связанные с выбранной и помещаем их в список pl
                            if (this.AllPoints[j][i] == this.InsidePoints[j][k][0])
                            {
                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][1]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][1]);
                                }

                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][2]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][2]);
                                }
                            }
                            else if (this.AllPoints[j][i] == this.InsidePoints[j][k][1])
                            {
                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][0]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][0]);
                                }

                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][2]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][2]);
                                }
                            }
                            else if (this.AllPoints[j][i] == this.InsidePoints[j][k][2])
                            {
                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][0]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][0]);
                                }

                                if (this.FindIndexInList(pl, this.InsidePoints[j][k][1]) == -1)
                                {
                                    pl.Add(this.InsidePoints[j][k][1]);
                                }
                            }
                        }

                        // Вычисляем новые координаты точки
                        X = 0;
                        Y = 0;
                        for (int k = 0; k < pl.Count; k++)
                        {
                            X += pl[k].X;
                            Y += pl[k].Y;
                        }

                        p.X = (int)Math.Round(X / pl.Count);
                        p.Y = (int)Math.Round(Y / pl.Count);

                        // Переприсваиваем новые координаты точки
                        for (int k = 0; k < this.InsidePoints[j].Count; k++)
                        {
                            if (this.InsidePoints[j][k][0] == this.AllPoints[j][i])
                            {
                                this.InsidePoints[j][k][0] = p;
                            }
                            else if (this.InsidePoints[j][k][1] == this.AllPoints[j][i])
                            {
                                this.InsidePoints[j][k][1] = p;
                            }
                            else if (this.InsidePoints[j][k][2] == this.AllPoints[j][i])
                            {
                                this.InsidePoints[j][k][2] = p;
                            }
                        }
                    }
                }
            }

            // Формируем список внутренних точек заново
            this.FillAllPoints();
        }

        /// <summary>
        /// The fill all points.
        /// </summary>
        private void FillAllPoints()
        {
            // Заполнение списка всех узлов
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Инициализация массива номеров КЭ
                this.TriangleNum[j] = new int[this.InsidePoints[j].Count];
            }

            int k = 0; // Счетчик КЭ
            this.AllPoints = new List<Point>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.AllPoints[i] = new List<Point>(i);
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.InsidePoints[j].Count; i++)
                {
                    if (this.FindIndexInList(this.AllPoints[j], this.InsidePoints[j][i][0]) == -1)
                    {
                        this.AllPoints[j].Add(this.InsidePoints[j][i][0]);
                    }

                    if (this.FindIndexInList(this.AllPoints[j], this.InsidePoints[j][i][1]) == -1)
                    {
                        this.AllPoints[j].Add(this.InsidePoints[j][i][1]);
                    }

                    if (this.FindIndexInList(this.AllPoints[j], this.InsidePoints[j][i][2]) == -1)
                    {
                        this.AllPoints[j].Add(this.InsidePoints[j][i][2]);
                    }

                    k++;
                    this.TriangleNum[j][i] = k;
                }
            }
        }

        /// <summary>
        /// Нахождение позиции точки в списке.
        /// </summary>
        /// <param name="list">
        /// список точке.
        /// </param>
        /// <param name="p">
        /// искомая точка.
        /// </param>
        /// <returns>
        /// номер точки в списке.
        /// </returns>
        private int FindIndexInList(List<Point> list, Point p)
        {
            int index = -1;
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i] == p)
                {
                    return i;
                }
            }

            return index;
        }

        /// <summary>
        /// The find index in array.
        /// </summary>
        /// <param name="array">
        /// The array.
        /// </param>
        /// <param name="p">
        /// The p.
        /// </param>
        /// <returns>
        /// The find index in array.
        /// </returns>
        private int FindIndexInArray(Point[] array, Point p)
        {
            // Нахождение позиции точки в массиве
            int index = -1;
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i] == p)
                {
                    return i;
                }
            }

            return index;
        }

        /// <summary>
        /// Формирование и построение сетки КЭ
        /// </summary>
        private void Mesh()
        {
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.ExternalFront = new Point[this.cZoneCount][];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.ExternalFront[i] = new Point[this.Front[i].Length];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.Front[i].Length; j++)
                {
                    this.ExternalFront[i][j] = this.Front[i][j];
                }
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                this.FrontZone = new GraphicsPath();
                this.FrontZone.StartFigure();
                this.FrontZone.AddLines(this.Front[j]);
                this.FrontZone.CloseFigure();
                this.eee.DrawPath(this.ZonePen, this.FrontZone);

                while (this.ExternalFront[j].Length > 3) // Если длина фронта ещё может быть разбита
                {
                    // for (int k = 0; k < 5; k++ )
                    {
                        // if (k == 2)
                    }

                    double MinAngle, temp;
                    int IndexMinAngle;
                    MinAngle = this.FindAngle(0, j);
                    IndexMinAngle = 0;
                    for (int i = 1; i < this.ExternalFront[j].Length; i++)
                    {
                        temp = this.FindAngle(i, j);
                        if (temp < MinAngle)
                        {
                            MinAngle = temp;
                            IndexMinAngle = i;
                        }
                    }

                    if ((MinAngle <= this.fMiterAngle) || ((MinAngle >= 89.99) && (MinAngle <= 90.01)))
                    {
                        int iLeftPoint = -1, iRightPoint = -1;
                        this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, j);
                        this.eee.DrawLine(
                            this.InsidePen, this.ExternalFront[j][iLeftPoint], this.ExternalFront[j][iRightPoint]);

                        var Triangle = new Point[3]; // Добавление треугольника к списку
                        Triangle[0] = this.ExternalFront[j][iLeftPoint];
                        Triangle[1] = this.ExternalFront[j][iRightPoint];
                        Triangle[2] = this.ExternalFront[j][IndexMinAngle];
                        this.InsidePoints[j].Add(Triangle);

                        this.DeletePoint(IndexMinAngle, j);
                    }
                    else
                    {
                        int iLeftPoint = -1, iRightPoint = -1;
                        this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, j);
                        Point oldPoint = this.ExternalFront[j][IndexMinAngle];

                        Point newPoint = this.AddPoint(IndexMinAngle, MinAngle, j);
                        if (this.bError)
                        {
                            return;
                        }

                        if ((newPoint.X > 0) && (newPoint.Y > 0))
                        {
                            this.eee.DrawLine(this.InsidePen, oldPoint, newPoint);
                            this.eee.DrawLine(this.InsidePen, newPoint, this.ExternalFront[j][iLeftPoint]);
                            this.eee.DrawLine(this.InsidePen, newPoint, this.ExternalFront[j][iRightPoint]);

                            Point[] Triangle1 = new Point[3], Triangle2 = new Point[3];
                                
                                // Добавление треугольников к списку
                            Triangle1[0] = this.ExternalFront[j][iLeftPoint];
                            Triangle1[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                            Triangle1[2] = newPoint;
                            this.InsidePoints[j].Add(Triangle1);
                            Triangle2[0] = this.ExternalFront[j][iRightPoint];
                            Triangle2[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                            Triangle2[2] = newPoint;
                            this.InsidePoints[j].Add(Triangle2);
                        }
                    }
                }

                // Добавляем последний треугольник к списку треугольников
                var TriangleLast = new Point[3]; // Добавление треугольников к списку
                TriangleLast[0] = this.ExternalFront[j][0];
                TriangleLast[1] = this.ExternalFront[j][1];
                TriangleLast[2] = this.ExternalFront[j][2];
                this.InsidePoints[j].Add(TriangleLast);
            }

            this.FillAllPoints();
        }

        /// <summary>
        /// The delete point.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        private void DeletePoint(int index, int FrontNum)
        {
            // Замена старого узла на новый
            int iLeftPoint = -1, iRightPoint = -1;
            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            this.TempFront = new Point[this.ExternalFront[FrontNum].Length];
            for (int i = 0; i < this.ExternalFront[FrontNum].Length; i++)
            {
                this.TempFront[i] = this.ExternalFront[FrontNum][i];
            }

            this.ExternalFront[FrontNum] = new Point[this.TempFront.Length - 1];
            for (int i = 0; i < index; i++)
            {
                this.ExternalFront[FrontNum][i] = this.TempFront[i];
            }

            for (int i = index; i < this.ExternalFront[FrontNum].Length; i++)
            {
                this.ExternalFront[FrontNum][i] = this.TempFront[i + 1];
            }

            this.FrontZone = new GraphicsPath();
            this.FrontZone.StartFigure();
            this.FrontZone.AddLines(this.ExternalFront[FrontNum]);
            this.FrontZone.CloseFigure();
        }

        /// <summary>
        /// The first criterion.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point FirstCriterion(int index, double AngleMin, int FrontNum)
        {
            // Первый критерий поиска нового узла
            var p = new Point(-1000, -1000);
            Point p_l = new Point(-1000, -1000), p_r = new Point(-1000, -1000);
                
                // Точки, возвращаемые функцией поиска новых координат
            Point p1 = new Point(-1000, -1000), p2 = new Point(-1000, -1000);
            int iLeftPoint = -1, iRightPoint = -1;
            double R, l3;

            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            R =
                (this.mathematic.FindDist(this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][index]) +
                 this.mathematic.FindDist(
                     this.ExternalFront[FrontNum][iRightPoint], this.ExternalFront[FrontNum][index])) / 2;
            l3 = this.mathematic.CosineLaw2(
                AngleMin / 2, 
                R, 
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]));
            this.mathematic.FindPoint(
                this.ExternalFront[FrontNum][index], 
                this.ExternalFront[FrontNum][iLeftPoint], 
                R, 
                l3, 
                this.FrontZone, 
                ref p_l, 
                ref p_r);
            if (p_r.X == -1000)
            {
                p = p_l;
            }
            else
            {
                l3 = this.mathematic.CosineLaw2(
                    AngleMin / 2, 
                    R, 
                    this.mathematic.FindDist(
                        this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]));
                this.mathematic.FindPoint(
                    this.ExternalFront[FrontNum][index], 
                    this.ExternalFront[FrontNum][iRightPoint], 
                    R, 
                    l3, 
                    this.FrontZone, 
                    ref p1, 
                    ref p2);
                if (p2.X == -1000)
                {
                    p = p1;
                }
                else
                {
                    if (((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p1.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p1.Y / this.multiplier)))) ||
                        ((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p2.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p2.Y / this.multiplier)))))
                    {
                        p = p_l;
                    }
                    else
                    {
                        p = p_r;
                    }
                }
            }

            return p;
        }

        /// <summary>
        /// The second criterion.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point SecondCriterion(int index, double AngleMin, int FrontNum)
        {
            // Второй критерий поиска нового узла
            var p = new Point(-1000, -1000);
            Point p_l = new Point(-1000, -1000), p_r = new Point(-1000, -1000);
                
                // Точки, возвращаемые функцией поиска новых координат
            Point p1 = new Point(-1000, -1000), p2 = new Point(-1000, -1000);
            int ind1 = 0, ind2 = 0;
            int iLeftPoint = -1, iRightPoint = -1;
            double R, l3;

            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            R =
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]) +
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]);
            this.FindLeftRightIndex2(iLeftPoint, ref ind1, ref ind2, FrontNum);
            R += this.mathematic.FindDist(this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][ind1]);
            this.FindLeftRightIndex2(iRightPoint, ref ind1, ref ind2, FrontNum);
            R += this.mathematic.FindDist(this.ExternalFront[FrontNum][iRightPoint], this.ExternalFront[FrontNum][ind2]);
            R = R / 4.0f;
            l3 = this.mathematic.CosineLaw2(
                AngleMin / 2, 
                R, 
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.Front[FrontNum][iLeftPoint]));
            this.mathematic.FindPoint(
                this.ExternalFront[FrontNum][index], 
                this.ExternalFront[FrontNum][iLeftPoint], 
                R, 
                l3, 
                this.FrontZone, 
                ref p_l, 
                ref p_r);
            if (p_r.X == -1000)
            {
                p = p_l;
            }
            else
            {
                l3 = this.mathematic.CosineLaw2(
                    AngleMin / 2, 
                    R, 
                    this.mathematic.FindDist(
                        this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]));
                this.mathematic.FindPoint(
                    this.ExternalFront[FrontNum][index], 
                    this.ExternalFront[FrontNum][iRightPoint], 
                    R, 
                    l3, 
                    this.FrontZone, 
                    ref p1, 
                    ref p2);
                if (p2.X == -1000)
                {
                    p = p1;
                }
                else
                {
                    if (((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p1.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p1.Y / this.multiplier)))) ||
                        ((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p2.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p2.Y / this.multiplier)))))
                    {
                        p = p_l;
                    }
                    else
                    {
                        p = p_r;
                    }
                }
            }

            return p;
        }

        /// <summary>
        /// The third criterion.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point ThirdCriterion(int index, double AngleMin, int FrontNum)
        {
            // Третий критерий поиска нового узла
            var p = new Point(-1000, -1000);
            int ind1 = 0, ind2 = 0;
            int iLeftPoint = -1, iRightPoint = -1;
            double R, l3;
            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            this.FindLeftRightIndex2(iLeftPoint, ref ind1, ref ind2, FrontNum);
            R =
                (this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]) +
                 this.mathematic.FindDist(this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][ind1])) /
                2.0;
            this.FindLeftRightIndex2(iRightPoint, ref ind1, ref ind2, FrontNum);
            l3 =
                (this.mathematic.FindDist(
                    this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]) +
                 this.mathematic.FindDist(this.ExternalFront[FrontNum][iRightPoint], this.ExternalFront[FrontNum][ind2])) /
                2.0;
            p = this.mathematic.FindPointFor34(
                this.ExternalFront[FrontNum][iLeftPoint], 
                this.ExternalFront[FrontNum][iRightPoint], 
                R, 
                l3, 
                this.ExternalFront[FrontNum][index], 
                this.FrontZone, 
                this.multiplier);
            return p;
        }

        /// <summary>
        /// The fourth criterion.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point FourthCriterion(int index, double AngleMin, int FrontNum)
        {
            // Четвертый критерий поиска нового узла
            var p = new Point(-1000, -1000);
            int ind1 = 0, ind2 = 0;
            int iLeftPoint = -1, iRightPoint = -1;
            double R, l3;
            double k = 0, b = 0;

            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            double Dist =
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]) +
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]);
            this.FindLeftRightIndex2(iLeftPoint, ref ind1, ref ind2, FrontNum);
            Dist += this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][ind1]);
            R =
                (this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]) +
                 this.mathematic.FindDist(this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][ind1])) /
                2.0;
            this.FindLeftRightIndex2(iRightPoint, ref ind1, ref ind2, FrontNum);
            Dist += this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iRightPoint], this.ExternalFront[FrontNum][ind2]);
            Dist = Dist / 4.0f;
            l3 =
                (this.mathematic.FindDist(
                    this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]) +
                 this.mathematic.FindDist(this.ExternalFront[FrontNum][iRightPoint], this.ExternalFront[FrontNum][ind2])) /
                2.0;
            p = this.mathematic.FindPointFor34(
                this.ExternalFront[FrontNum][iLeftPoint], 
                this.ExternalFront[FrontNum][iRightPoint], 
                R, 
                l3, 
                this.ExternalFront[FrontNum][index], 
                this.FrontZone, 
                this.multiplier);
            this.mathematic.FindLineEquation(this.ExternalFront[FrontNum][index], p, ref k, ref b);
            p = this.mathematic.FindNewCoord(k, b, this.ExternalFront[FrontNum][index], Dist, this.FrontZone);
            return p;
        }

        /// <summary>
        /// The fifth criterion.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point FifthCriterion(int index, double AngleMin, int FrontNum)
        {
            // Пятый критерий поиска нового узла
            var p = new Point(-1000, -1000);
            Point p_l = new Point(-1000, -1000), p_r = new Point(-1000, -1000);
                
                // Точки, возвращаемые функцией поиска новых координат
            Point p1 = new Point(-1000, -1000), p2 = new Point(-1000, -1000);
            int iLeftPoint = -1, iRightPoint = -1;
            double R, l3;

            this.FindLeftRightIndex2(index, ref iLeftPoint, ref iRightPoint, FrontNum);
            R = this.mathematic.FindDensityFuncInPoint(
                this.ExternalFront[FrontNum][index], 
                this.DensityPoints[FrontNum], 
                this.DensityValues[FrontNum], 
                this.AvgDensityFunction, 
                this.multiplier);
            l3 = this.mathematic.CosineLaw2(
                AngleMin / 2, 
                R, 
                this.mathematic.FindDist(this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]));
            this.mathematic.FindPoint(
                this.ExternalFront[FrontNum][index], 
                this.ExternalFront[FrontNum][iLeftPoint], 
                R, 
                l3, 
                this.FrontZone, 
                ref p_l, 
                ref p_r);
            if (p_r.X == -1000)
            {
                p = p_l;
            }
            else
            {
                l3 = this.mathematic.CosineLaw2(
                    AngleMin / 2, 
                    R, 
                    this.mathematic.FindDist(
                        this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]));
                this.mathematic.FindPoint(
                    this.ExternalFront[FrontNum][index], 
                    this.ExternalFront[FrontNum][iRightPoint], 
                    R, 
                    l3, 
                    this.FrontZone, 
                    ref p1, 
                    ref p2);
                if (p2.X == -1000)
                {
                    p = p1;
                }
                else
                {
                    if (((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p1.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p1.Y / this.multiplier)))) ||
                        ((Math.Round((double)(p_l.X / this.multiplier)) == Math.Round((double)(p2.X / this.multiplier))) &&
                         (Math.Round((double)(p_l.Y / this.multiplier)) == Math.Round((double)(p2.Y / this.multiplier)))))
                    {
                        p = p_l;
                    }
                    else
                    {
                        p = p_r;
                    }
                }
            }

            for (int j = 0; j < 1000; j++)
            {
                if (p.X != -1000)
                {
                    break;
                }

                R = R * 0.99;
                l3 = this.mathematic.CosineLaw2(
                    AngleMin / 2, 
                    R, 
                    this.mathematic.FindDist(
                        this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iLeftPoint]));
                this.mathematic.FindPoint(
                    this.ExternalFront[FrontNum][index], 
                    this.ExternalFront[FrontNum][iLeftPoint], 
                    R, 
                    l3, 
                    this.FrontZone, 
                    ref p_l, 
                    ref p_r);
                if (p_r.X == -1000)
                {
                    p = p_l;
                }
                else
                {
                    l3 = this.mathematic.CosineLaw2(
                        AngleMin / 2, 
                        R, 
                        this.mathematic.FindDist(
                            this.ExternalFront[FrontNum][index], this.ExternalFront[FrontNum][iRightPoint]));
                    this.mathematic.FindPoint(
                        this.ExternalFront[FrontNum][index], 
                        this.ExternalFront[FrontNum][iLeftPoint], 
                        R, 
                        l3, 
                        this.FrontZone, 
                        ref p1, 
                        ref p2);
                    if (p2.X == -1000)
                    {
                        p = p1;
                    }
                    else
                    {
                        if ((Math.Round((double)(p_l.X / this.multiplier)) ==
                             Math.Round((double)(p1.X / this.multiplier))) ||
                            (Math.Round((double)(p_l.X / this.multiplier)) ==
                             Math.Round((double)(p2.X / this.multiplier))))
                        {
                            p = p_l;
                        }
                        else
                        {
                            p = p_r;
                        }
                    }
                }
            }

            return p;
        }

        /// <summary>
        /// The add point.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        /// <param name="AngleMin">
        /// The angle min.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// </returns>
        private Point AddPoint(int index, double AngleMin, int FrontNum)
        {
            // Построение нового узла
            var p = new Point();
            switch (this.iMeshCriterion)
            {
                    // Критерий построения нового узла
                case 0:
                    {
                        p = this.FirstCriterion(index, AngleMin, FrontNum);
                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (2)
                            p = this.SecondCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (3)
                            p = this.ThirdCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (4)
                            p = this.FourthCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если точка так и не найдена, построение сетки завершается и выводится сообщение об ошибке
                            this.bError = true;
                            return new Point(-1000, -1000);
                        }
                    }

                    break;
                case 1:
                    {
                        p = this.SecondCriterion(index, AngleMin, FrontNum);
                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (1)
                            p = this.FirstCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (3)
                            p = this.ThirdCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (4)
                            p = this.FourthCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если точка так и не найдена, построение сетки завершается и выводится сообщение об ошибке
                            this.bError = true;
                            return new Point(-1000, -1000);
                        }
                    }

                    break;
                case 2:
                    {
                        p = this.ThirdCriterion(index, AngleMin, FrontNum);
                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (1)
                            p = this.FirstCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (2)
                            p = this.SecondCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (4)
                            p = this.FourthCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если точка так и не найдена, построение сетки завершается и выводится сообщение об ошибке
                            this.bError = true;
                            return new Point(-1000, -1000);
                        }
                    }

                    break;
                case 3:
                    {
                        p = this.FourthCriterion(index, AngleMin, FrontNum);
                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (1)
                            p = this.FirstCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (2)
                            p = this.SecondCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если искомая точка не найдена, используем другие критерии (3)
                            p = this.ThirdCriterion(index, AngleMin, FrontNum);
                        }

                        if (p.X == -1000)
                        {
                            // Если точка так и не найдена, построение сетки завершается и выводится сообщение об ошибке
                            this.bError = true;
                            return new Point(-1000, -1000);
                        }
                    }

                    break;
                case 4:
                    {
                        p = this.FifthCriterion(index, AngleMin, FrontNum);
                        if (p.X == -1000)
                        {
                            // Если точка так и не найдена, построение сетки завершается и выводится сообщение об ошибке
                            this.bError = true;
                            return new Point(-1000, -1000);
                        }
                    }

                    break;
            }

            this.ExternalFront[FrontNum][index] = p;

            this.FrontZone = new GraphicsPath();
            this.FrontZone.StartFigure();
            this.FrontZone.AddLines(this.ExternalFront[FrontNum]);
            this.FrontZone.CloseFigure();

            return p;
        }

        /// <summary>
        /// The find angle.
        /// </summary>
        /// <param name="IndexInFront">
        /// The index in front.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        /// <returns>
        /// The find angle.
        /// </returns>
        private double FindAngle(int IndexInFront, int FrontNum)
        {
            // Нахождение минимального угла
            double angle = 0;
            int iLeftPoint = -1, iRightPoint = -1;
            this.FindLeftRightIndex2(IndexInFront, ref iLeftPoint, ref iRightPoint, FrontNum);
            double a, b, c;
            a = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][iRightPoint]);
            b = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][IndexInFront], this.ExternalFront[FrontNum][iRightPoint]);
            c = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][IndexInFront]);
            angle = this.mathematic.CosineLaw(a, b, c);

            var p = new Point();
            p.X = this.ExternalFront[FrontNum][iLeftPoint].X +
                  (this.ExternalFront[FrontNum][iRightPoint].X - this.ExternalFront[FrontNum][iLeftPoint].X) / 2;
            p.Y = this.ExternalFront[FrontNum][iLeftPoint].Y +
                  (this.ExternalFront[FrontNum][iRightPoint].Y - this.ExternalFront[FrontNum][iLeftPoint].Y) / 2;
            if (!this.FrontZone.IsVisible(p))
            {
                angle = 360 - angle;
            }

            return angle;
        }

        /// <summary>
        /// Измененная процедура поиска.
        /// </summary>
        /// <param name="IndexInFront">
        /// </param>
        /// <param name="FrontNum">
        /// </param>
        /// <returns>
        /// The find angle changed from original.
        /// </returns>
        private double FindAngleChangedFromOriginal(int IndexInFront, int FrontNum)
        {
            // Нахождение минимального угла
            double angle = 0;
            int iLeftPoint = -1, iRightPoint = -1;
            this.FindLeftRightIndex2(IndexInFront, ref iLeftPoint, ref iRightPoint, FrontNum);
            double a, b, c;
            a = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][iRightPoint]);
            b = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][IndexInFront], this.ExternalFront[FrontNum][iRightPoint]);
            c = this.mathematic.FindDist(
                this.ExternalFront[FrontNum][iLeftPoint], this.ExternalFront[FrontNum][IndexInFront]);
            angle = this.mathematic.CosineLaw(a, b, c);

            var p = new Point();
            p.X = this.ExternalFront[FrontNum][iLeftPoint].X +
                  (this.ExternalFront[FrontNum][iRightPoint].X - this.ExternalFront[FrontNum][iLeftPoint].X) / 2;
            p.Y = this.ExternalFront[FrontNum][iLeftPoint].Y +
                  (this.ExternalFront[FrontNum][iRightPoint].Y - this.ExternalFront[FrontNum][iLeftPoint].Y) / 2;

            // if (!FrontZone.IsVisible(p)) angle = 360 - angle;
            return angle;
        }

        // Нахождение индексов соседних точек
        /// <summary>
        /// The find left right index.
        /// </summary>
        /// <param name="IndexInFront">
        /// The index in front.
        /// </param>
        /// <param name="iLeftPoint">
        /// The i left point.
        /// </param>
        /// <param name="iRightPoint">
        /// The i right point.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        private void FindLeftRightIndex(int IndexInFront, ref int iLeftPoint, ref int iRightPoint, int FrontNum)
        {
            if (IndexInFront > 0)
            {
                iLeftPoint = IndexInFront - 1;
            }
            else
            {
                iLeftPoint = this.Front[FrontNum].Length - 1;
            }

            if (IndexInFront < this.Front[FrontNum].Length - 1)
            {
                iRightPoint = IndexInFront + 1;
            }
            else
            {
                iRightPoint = 0;
            }
        }

        // Нахождение индексов соседних точек
        /// <summary>
        /// The find left right index 2.
        /// </summary>
        /// <param name="IndexInFront">
        /// The index in front.
        /// </param>
        /// <param name="iLeftPoint">
        /// The i left point.
        /// </param>
        /// <param name="iRightPoint">
        /// The i right point.
        /// </param>
        /// <param name="FrontNum">
        /// The front num.
        /// </param>
        private void FindLeftRightIndex2(int IndexInFront, ref int iLeftPoint, ref int iRightPoint, int FrontNum)
        {
            if (IndexInFront > 0)
            {
                iLeftPoint = IndexInFront - 1;
            }
            else
            {
                iLeftPoint = this.ExternalFront[FrontNum].Length - 1;
            }

            if (IndexInFront < this.ExternalFront[FrontNum].Length - 1)
            {
                iRightPoint = IndexInFront + 1;
            }
            else
            {
                iRightPoint = 0;
            }
        }

        /// <summary>
        /// The equal mesh.
        /// </summary>
        /// <param name="step">
        /// The step.
        /// </param>
        private void EqualMesh(double step)
        {
            // Разбиение сторон зон на равные отрезки длиной step
            var PointOnCircle = new List<Point[]>(1); // Список пар точек, лежащих на дуге
            var PointPair = new List<Point[]>(1);
            var NewFrontPoints = new List<Point>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                NewFrontPoints[i] = new List<Point>(1);
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Изначально задаём все фронты как наборы основных точек зон
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    NewFrontPoints[i].Add(this.ZonesPoints[i][j]);
                }
            }

            List<Point> TempPoints;
            Point p1, p2, p;
            p = new Point();
            double fSide, newStep;
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                PointOnCircle = new List<Point[]>(1);
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    // И для каждой точки
                    TempPoints = new List<Point>(1); // Все добавляемые точки

                    // -------------------- Блок проверки на окружность -----------------------
                    Point pc1, pc2, pc3, pO;
                    if (i == 0)
                    {
                        pc1 = this.ZonesPoints[j][this.cPointsInZone - 1];
                        pc2 = this.ZonesPoints[j][0];
                        pc3 = this.ZonesPoints[j][1];
                    }
                    else if (i < this.cPointsInZone - 2)
                    {
                        pc1 = this.ZonesPoints[j][i - 1];
                        pc2 = this.ZonesPoints[j][i];
                        pc3 = this.ZonesPoints[j][i + 1];
                    }
                    else if (i == this.cPointsInZone - 2)
                    {
                        pc1 = this.ZonesPoints[j][i - 1];
                        pc2 = this.ZonesPoints[j][i];
                        pc3 = this.ZonesPoints[j][i + 1];
                    }
                    else
                    {
                        pc1 = this.ZonesPoints[j][i - 1];
                        pc2 = this.ZonesPoints[j][i];
                        pc3 = this.ZonesPoints[j][0];
                    }

                    pO = this.mathematic.IsCircle(pc1, pc2, pc3, this.fRoundingRadius, this.multiplier);
                        
                        // Находим координаты центра окружности

                    if (pO.X > -1000)
                    {
                        // Если точки лежат на дуге
                        var pairPoint1 = new Point[2];
                        var pairPoint2 = new Point[2];
                        pairPoint1[0] = pc1;
                        pairPoint1[1] = pc2;
                        pairPoint2[0] = pc2;
                        pairPoint2[1] = pc3;
                        PointOnCircle.Add(pairPoint1);
                        PointOnCircle.Add(pairPoint2);

                        // pO.X = (int)(Math.Round((double)pO.X / multiplier) * multiplier);
                        // pO.Y = (int)(Math.Round((double)pO.Y / multiplier) * multiplier);
                        double fCircleLen; // Длина фрагмента дуги
                        double fAngle; // Угол напротив фрагмента дуги

                        // ---------- Первый фрагмент дуги ----------
                        fAngle = this.mathematic.CosineLaw(
                            this.mathematic.FindDist(pc1, pc2), 
                            this.mathematic.FindDist(pO, pc1), 
                            this.mathematic.FindDist(pO, pc2));
                        fCircleLen = Math.PI * this.fRoundingRadius * fAngle / 180;
                        newStep = this.mathematic.FindNewStep(fCircleLen, step); // Новый шаг разбиения

                        for (int k = ((int)Math.Round(fCircleLen / newStep)) - 1; k >= 1; k--)
                        {
                            // Координаты всех добавляемых точек
                            double alpha, a;
                            alpha = 180.0 * newStep * k / (Math.PI * this.fRoundingRadius);
                            a = this.mathematic.CosineLaw2(fAngle - alpha, this.fRoundingRadius, this.fRoundingRadius);
                            p = this.mathematic.FindPointOnCircle(pO, pc1, this.fRoundingRadius, a, pc2);
                            this.eee.FillEllipse(
                                this.InterPointsBrush, 
                                p.X - this.fInterPointSize, 
                                p.Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            if (p.X == -1000)
                            {
                                continue;
                            }

                            TempPoints.Add(p);
                        }

                        int posc1 = -1, posc2 = -1; // Позиции фронта, между которыми добавим новые точки
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            if (pc1 == NewFrontPoints[j][k])
                            {
                                posc1 = k;
                            }

                            if (pc2 == NewFrontPoints[j][k])
                            {
                                posc2 = k;
                            }
                        }

                        // Добавляем точки
                        this.TempFront = new Point[NewFrontPoints[j].Count];
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            this.TempFront[k] = NewFrontPoints[j][k];
                        }

                        if ((posc2 > posc1) && (TempPoints.Count > 0))
                        {
                            if ((Math.Abs(NewFrontPoints[j][posc1].X - TempPoints[0].X) >=
                                 Math.Abs(NewFrontPoints[j][posc2].X - TempPoints[0].X)) &&
                                (Math.Abs(NewFrontPoints[j][posc1].Y - TempPoints[0].Y) >=
                                 Math.Abs(NewFrontPoints[j][posc2].Y - TempPoints[0].Y)))
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k <= posc1; k++)
                                {
                                    // Перестраиваем фронт
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = TempPoints.Count - 1; k >= 0; k--)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }

                                for (int k = posc2; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }
                            }
                            else
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k <= posc1; k++)
                                {
                                    // Перестраиваем фронт
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }

                                for (int k = posc2; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }
                            }
                        }
                        else if (TempPoints.Count > 0)
                        {
                            // Размещаем точки в конце фронта
                            if ((Math.Abs(NewFrontPoints[j][posc1].X - TempPoints[0].X) >=
                                 Math.Abs(NewFrontPoints[j][posc2].X - TempPoints[0].X)) &&
                                (Math.Abs(NewFrontPoints[j][posc1].Y - TempPoints[0].Y) >=
                                 Math.Abs(NewFrontPoints[j][posc2].Y - TempPoints[0].Y)))
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }
                            }
                            else
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[TempPoints.Count - k - 1]);
                                }
                            }
                        }

                        // ---------- Второй фрагмент дуги ----------
                        TempPoints = new List<Point>(1); // Все добавляемые точки
                        fAngle = this.mathematic.CosineLaw(
                            this.mathematic.FindDist(pc2, pc3), 
                            this.mathematic.FindDist(pO, pc2), 
                            this.mathematic.FindDist(pO, pc3));
                        fCircleLen = Math.PI * this.fRoundingRadius * fAngle / 180;
                        newStep = this.mathematic.FindNewStep(fCircleLen, step); // Новый шаг разбиения

                        for (int k = (int)(fCircleLen / newStep) - 1; k >= 1; k--)
                        {
                            // Координаты всех добавляемых точек
                            double alpha, a;
                            alpha = 180.0 * newStep * k / (Math.PI * this.fRoundingRadius);
                            a = this.mathematic.CosineLaw2(alpha, this.fRoundingRadius, this.fRoundingRadius);
                            p = this.mathematic.FindPointOnCircle(pO, pc2, this.fRoundingRadius, a, pc3);
                            this.eee.FillEllipse(
                                this.InterPointsBrush, 
                                p.X - this.fInterPointSize, 
                                p.Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            if (p.X == -1000)
                            {
                                continue;
                            }

                            TempPoints.Add(p);
                        }

                        posc1 = -1;
                        posc2 = -1; // Позиции фронта, между которыми добавим новые точки
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            if (pc2 == NewFrontPoints[j][k])
                            {
                                posc1 = k;
                            }

                            if (pc3 == NewFrontPoints[j][k])
                            {
                                posc2 = k;
                            }
                        }

                        // Добавляем точки
                        this.TempFront = new Point[NewFrontPoints[j].Count];
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            this.TempFront[k] = NewFrontPoints[j][k];
                        }

                        if ((posc2 > posc1) && (TempPoints.Count > 0))
                        {
                            if ((Math.Abs(NewFrontPoints[j][posc1].X - TempPoints[0].X) <=
                                 Math.Abs(NewFrontPoints[j][posc2].X - TempPoints[0].X)) &&
                                (Math.Abs(NewFrontPoints[j][posc1].Y - TempPoints[0].Y) <=
                                 Math.Abs(NewFrontPoints[j][posc2].Y - TempPoints[0].Y)))
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k <= posc1; k++)
                                {
                                    // Перестраиваем фронт
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }

                                for (int k = posc2; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }
                            }
                            else
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k <= posc1; k++)
                                {
                                    // Перестраиваем фронт
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = TempPoints.Count - 1; k >= 0; k--)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }

                                for (int k = posc2; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }
                            }
                        }
                        else if (TempPoints.Count > 0)
                        {
                            // Размещаем точки в конце фронта
                            if ((Math.Abs(NewFrontPoints[j][posc1].X - TempPoints[0].X) >=
                                 Math.Abs(NewFrontPoints[j][posc2].X - TempPoints[0].X)) &&
                                (Math.Abs(NewFrontPoints[j][posc1].Y - TempPoints[0].Y) >=
                                 Math.Abs(NewFrontPoints[j][posc2].Y - TempPoints[0].Y)))
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[TempPoints.Count - k - 1]);
                                }
                            }
                            else
                            {
                                NewFrontPoints[j] = new List<Point>(1);
                                for (int k = 0; k < this.TempFront.Length; k++)
                                {
                                    NewFrontPoints[j].Add(this.TempFront[k]);
                                }

                                for (int k = 0; k < TempPoints.Count; k++)
                                {
                                    NewFrontPoints[j].Add(TempPoints[k]);
                                }
                            }
                        }

                        if (i != 0)
                        {
                            i++;
                        }

                        continue;
                    }

                    // --------------------------------------------------------------------------
                }

                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    TempPoints = new List<Point>(1); // Все добавляемые точки

                    p1 = this.ZonesPoints[j][i];
                    if (i == this.cPointsInZone - 1)
                    {
                        p2 = this.ZonesPoints[j][0];
                    }
                    else
                    {
                        p2 = this.ZonesPoints[j][i + 1];
                    }

                    bool bContinue = false;
                    for (int k = 0; k < PointOnCircle.Count; k++)
                    {
                        if (((p1 == PointOnCircle[k][0]) && (p2 == PointOnCircle[k][1])) ||
                            ((p2 == PointOnCircle[k][0]) && (p1 == PointOnCircle[k][1])))
                        {
                            bContinue = true;
                            break;
                        }
                    }

                    if (bContinue)
                    {
                        continue;
                    }

                    // Поиск данной пары точек в предыдущих зонах
                    Point op1 = new Point(-1000, -1000), op2 = new Point(-1000, -1000);
                    int ZoneNum = -1; // Номер зоны, в которой найден совпадающий отрезок точек
                    bool bDiversion = false;
                        
                        // Признак смены направления обхода точек(необходимо при копировании уже найденных точек)
                    for (int k = 0; k < j; k++)
                    {
                        op1 = new Point(-1000, -1000); // Точки с совпадающими координатами
                        op2 = new Point(-1000, -1000);
                        int k1 = -1, k2 = -1; // Вспомогательные переменные
                        for (int m = 0; m < this.cPointsInZone; m++)
                        {
                            if (this.ZonesPoints[k][m] == p1)
                            {
                                op1 = p1;
                                k1 = k;
                                if (k1 == k2)
                                {
                                    // Если обе точки находятся в одной зоне, запоминаем номер зоны
                                    if (m != this.cPointsInZone - 1)
                                    {
                                        bDiversion = true; // Если 2-я точка найдена раньше 1-й, порядок обратный
                                    }

                                    ZoneNum = k1; // пара точек найдена в зоне № k
                                    break;
                                }
                            }

                            if (this.ZonesPoints[k][m] == p2)
                            {
                                op2 = p2;
                                k2 = k;
                                if (k1 == k2)
                                {
                                    // Если обе точки находятся в одной зоне, запоминаем номер зоны
                                    if (m == this.cPointsInZone - 1)
                                    {
                                        bDiversion = true; // Если 2-я точка найдена раньше 1-й, порядок обратный
                                    }
                                    else
                                    {
                                        bDiversion = false;
                                    }

                                    ZoneNum = k1; // пара точек найдена в зоне № k
                                    break;
                                }
                            }
                        }
                    }

                    int pos1 = -1, pos2 = -1; // Позиции фронта, между которыми добавим новые точки
                    for (int k = 0; k < NewFrontPoints[j].Count; k++)
                    {
                        if (p1 == NewFrontPoints[j][k])
                        {
                            pos1 = k;
                        }

                        if (p2 == NewFrontPoints[j][k])
                        {
                            pos2 = k;
                        }
                    }

                    if (ZoneNum == -1)
                    {
                        // если пара точек не найдена
                        fSide = this.mathematic.FindDist(p1, p2); // Сторона разбиения
                        newStep = this.mathematic.FindNewStep(fSide, step); // Шаг разбиения

                        for (int k = (int)(fSide / newStep) - 1; k >= 1; k--)
                        {
                            // Координаты всех добавляемых точек
                            p.X = (int)Math.Round(newStep * k * (p1.X - p2.X) / fSide + p2.X);
                            p.Y = (int)Math.Round(newStep * k * (p1.Y - p2.Y) / fSide + p2.Y);
                            this.eee.FillEllipse(
                                this.InterPointsBrush, 
                                p.X - this.fInterPointSize, 
                                p.Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            TempPoints.Add(p);
                        }

                        // Добавляем точки
                        this.TempFront = new Point[NewFrontPoints[j].Count];
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            this.TempFront[k] = NewFrontPoints[j][k];
                        }

                        if (pos2 > pos1)
                        {
                            NewFrontPoints[j] = new List<Point>(1);
                            for (int k = 0; k <= pos1; k++)
                            {
                                // Перестраиваем фронт
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }

                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                NewFrontPoints[j].Add(TempPoints[k]);
                            }

                            for (int k = pos2; k < this.TempFront.Length; k++)
                            {
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }
                        }
                        else
                        {
                            // Размещаем точки в конце фронта
                            NewFrontPoints[j] = new List<Point>(1);
                            for (int k = 0; k < this.TempFront.Length; k++)
                            {
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }

                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                NewFrontPoints[j].Add(TempPoints[k]);
                            }
                        }
                    }
                    else
                    {
                        // если пара точек найдена, копируем данные из уже имеющихся
                        int opos1 = -1, opos2 = -1;
                            
                            // Позиции фронта второй зоны, между которыми расположены искомые точки
                        if (bDiversion)
                        {
                            for (int k = 0; k < NewFrontPoints[ZoneNum].Count; k++)
                            {
                                if (p1 == NewFrontPoints[ZoneNum][k])
                                {
                                    opos2 = k;
                                }

                                if (p2 == NewFrontPoints[ZoneNum][k])
                                {
                                    opos1 = k;
                                }
                            }
                        }
                        else
                        {
                            for (int k = 0; k < NewFrontPoints[ZoneNum].Count; k++)
                            {
                                if (p1 == NewFrontPoints[ZoneNum][k])
                                {
                                    opos1 = k;
                                }

                                if (p2 == NewFrontPoints[ZoneNum][k])
                                {
                                    opos2 = k;
                                }
                            }
                        }

                        if (opos2 > opos1)
                        {
                            for (int k = opos1 + 1; k < opos2; k++)
                            {
                                TempPoints.Add(NewFrontPoints[ZoneNum][k]);
                            }
                        }
                        else if (opos2 == 0)
                        {
                            // Если точки расположены в конце фронта
                            for (int k = opos1 + 1; k < NewFrontPoints[ZoneNum].Count; k++)
                            {
                                TempPoints.Add(NewFrontPoints[ZoneNum][k]);
                            }
                        }
                        else
                        {
                            // Если точки расположены в обратном порядке
                            for (int k = opos1 - 1; k > opos2; k--)
                            {
                                TempPoints.Add(NewFrontPoints[ZoneNum][k]);
                            }
                        }

                        if (bDiversion)
                        {
                            // Инвертируем список
                            this.TempFront = new Point[TempPoints.Count];
                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                this.TempFront[k] = TempPoints[TempPoints.Count - 1 - k];
                            }

                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                TempPoints[k] = this.TempFront[k];
                            }
                        }

                        // Добавляем точки
                        this.TempFront = new Point[NewFrontPoints[j].Count];
                        for (int k = 0; k < NewFrontPoints[j].Count; k++)
                        {
                            this.TempFront[k] = NewFrontPoints[j][k];
                        }

                        if (pos2 > pos1)
                        {
                            NewFrontPoints[j] = new List<Point>(1);
                            for (int k = 0; k <= pos1; k++)
                            {
                                // Перестраиваем фронт
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }

                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                NewFrontPoints[j].Add(TempPoints[k]);
                            }

                            for (int k = pos2; k < this.TempFront.Length; k++)
                            {
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }
                        }
                        else
                        {
                            // Размещаем точки в конце фронта
                            NewFrontPoints[j] = new List<Point>(1);
                            for (int k = 0; k < this.TempFront.Length; k++)
                            {
                                NewFrontPoints[j].Add(this.TempFront[k]);
                            }

                            for (int k = 0; k < TempPoints.Count; k++)
                            {
                                NewFrontPoints[j].Add(TempPoints[k]);
                            }
                        }
                    }
                }
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Копируем полученные данные во фронты
                this.Front[j] = new Point[NewFrontPoints[j].Count];
                for (int i = 0; i < this.Front[j].Length; i++)
                {
                    this.Front[j][i] = NewFrontPoints[j][i];
                }
            }
        }

        /// <summary>
        /// The add paint point.
        /// </summary>
        /// <param name="MinDist">
        /// The min dist.
        /// </param>
        /// <param name="newPoint">
        /// The new point.
        /// </param>
        /// <param name="z1">
        /// The z 1.
        /// </param>
        /// <param name="lp1">
        /// The lp 1.
        /// </param>
        /// <param name="lp2">
        /// The lp 2.
        /// </param>
        /// <param name="bCircle">
        /// The b circle.
        /// </param>
        private void AddPaintPoint(double MinDist, Point newPoint, int z1, Point lp1, Point lp2, bool bCircle)
        {
            // Добавление и рисование новой точки на стороне зоны
            if (MinDist <= this.fPointSize * 0.75f)
            {
                // Если расстояние от точки до прямой не превышает допустимого
                double Min1 = 1000; // Минимальные расстояния до точек фронта (будут соседними во фронте)
                int pos1 = 0, pos2 = 0; // Позиции, ограничивающие часть фронта
                int n1 = -1, n2 = -1; // точки, между которыми будет добавлена новая точка
                for (int i = 0; i < this.Front[z1].Length; i++)
                {
                    if (this.Front[z1][i] == lp1)
                    {
                        pos1 = i;
                    }
                    else if (this.Front[z1][i] == lp2)
                    {
                        pos2 = i;
                    }
                }

                if (pos2 > pos1)
                {
                    for (int i = pos1; i < pos2; i++)
                    {
                        if (bCircle)
                        {
                            // Если точка лежит на дуге
                            if (((newPoint.X < this.Front[z1][i].X) && (newPoint.X > this.Front[z1][i + 1].X)) ||
                                ((newPoint.X > this.Front[z1][i].X) && (newPoint.X < this.Front[z1][i + 1].X)) ||
                                ((newPoint.Y < this.Front[z1][i].Y) && (newPoint.Y > this.Front[z1][i + 1].Y)) ||
                                ((newPoint.Y > this.Front[z1][i].Y) && (newPoint.Y < this.Front[z1][i + 1].Y)))
                            {
                                n1 = i;
                                n2 = i + 1;
                                break;
                            }
                        }
                        else if (((this.mathematic.FindDist(this.Front[z1][i], this.Front[z1][i + 1]) - 0.3f) <=
                                  (this.mathematic.FindDist(this.Front[z1][i], newPoint) +
                                   this.mathematic.FindDist(this.Front[z1][i + 1], newPoint))) &&
                                 ((this.mathematic.FindDist(this.Front[z1][i], this.Front[z1][i + 1]) + 0.3f) >=
                                  (this.mathematic.FindDist(this.Front[z1][i], newPoint) +
                                   this.mathematic.FindDist(this.Front[z1][i + 1], newPoint))))
                        {
                            n1 = i;
                            n2 = i + 1;
                            break;
                        }
                    }
                }
                else
                {
                    for (int i = pos1; i < this.Front[z1].Length - 1; i++)
                    {
                        if (bCircle)
                        {
                            // Если точка лежит на дуге
                            if (((newPoint.X < this.Front[z1][i].X) && (newPoint.X > this.Front[z1][i + 1].X)) ||
                                ((newPoint.X > this.Front[z1][i].X) && (newPoint.X < this.Front[z1][i + 1].X)) ||
                                ((newPoint.Y < this.Front[z1][i].Y) && (newPoint.Y > this.Front[z1][i + 1].Y)) ||
                                ((newPoint.Y > this.Front[z1][i].Y) && (newPoint.Y < this.Front[z1][i + 1].Y)))
                            {
                                n1 = i;
                                n2 = i + 1;
                                break;
                            }
                        }
                        else if (((this.mathematic.FindDist(this.Front[z1][i], this.Front[z1][i + 1]) - 0.3f) <=
                                  (this.mathematic.FindDist(this.Front[z1][i], newPoint) +
                                   this.mathematic.FindDist(this.Front[z1][i + 1], newPoint))) &&
                                 ((this.mathematic.FindDist(this.Front[z1][i], this.Front[z1][i + 1]) + 0.3f) >=
                                  (this.mathematic.FindDist(this.Front[z1][i], newPoint) +
                                   this.mathematic.FindDist(this.Front[z1][i + 1], newPoint))))
                        {
                            n1 = i;
                            n2 = i + 1;
                            break;
                        }
                    }
                }

                if (n1 < 0)
                {
                    // Если точки так и не найдены, значит они в конце фронта
                    n1 = this.Front[z1].Length - 1;
                    n2 = 0;
                }

                // Находим наиближайшую точку к новой
                Min1 = 1000;

                // for (int i = 0; i < cZoneCount; i++)
                for (int j = 0; j < this.Front[z1].Length; j++)
                {
                    if (this.mathematic.FindDist(newPoint, this.Front[z1][j]) < Min1)
                    {
                        Min1 = this.mathematic.FindDist(newPoint, this.Front[z1][j]);
                    }
                }

                if (Min1 > 2 * this.fPointSize)
                {
                    // Если поблизости нет точек, строим данную точку
                    this.eee.FillEllipse(
                        this.InterPointsBrush, 
                        newPoint.X - this.fInterPointSize, 
                        newPoint.Y - this.fInterPointSize, 
                        this.fPointSize * 2 / 3, 
                        this.fPointSize * 2 / 3);
                    this.TempFront = new Point[this.Front[z1].Length];
                    for (int i = 0; i < this.Front[z1].Length; i++)
                    {
                        this.TempFront[i] = this.Front[z1][i];
                    }

                    this.Front[z1] = new Point[this.TempFront.Length + 1];

                    if (n2 == 0)
                    {
                        // Добавляем точку в конец фронта
                        for (int i = 0; i < this.Front[z1].Length - 1; i++)
                        {
                            this.Front[z1][i] = this.TempFront[i];
                        }

                        this.Front[z1][this.Front[z1].Length - 1] = newPoint;
                    }
                    else
                    {
                        for (int i = 0; i <= n1; i++)
                        {
                            this.Front[z1][i] = this.TempFront[i];
                        }

                        this.Front[z1][n1 + 1] = newPoint;
                        for (int i = n2 + 1; i < this.Front[z1].Length; i++)
                        {
                            this.Front[z1][i] = this.TempFront[i - 1];
                        }
                    }
                }
            }
        }

        /// <summary>
        /// The test finite element mesh.
        /// </summary>
        private void TestFiniteElementMesh()
        {
            // Тест сетки КЭ
            this.BadTrianglesNum = new List<int>[this.cZoneCount];
                
                // Инициализация списка "плохих" треугольников для каждой зоны
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadTrianglesNum[i] = new List<int>(1);
            }

            this.BadAngleNum = new List<int>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadAngleNum[i] = new List<int>(1);
            }

            this.BadAngle = new List<double[]>[this.cZoneCount];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.BadAngle[i] = new List<double[]>(1);
            }

            this.MinSquare = this.mathematic.GeronLaw(
                this.InsidePoints[0][0][0], this.InsidePoints[0][0][1], this.InsidePoints[0][0][2], this.multiplier);
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Поиск треугольников с малой площадью
                for (int i = 0; i < this.InsidePoints[j].Count; i++)
                {
                    if (
                        this.mathematic.GeronLaw(
                            this.InsidePoints[j][i][0], 
                            this.InsidePoints[j][i][1], 
                            this.InsidePoints[j][i][2], 
                            this.multiplier) < this.MinAllowSquare)
                    {
                        this.BadTrianglesNum[j].Add(i);
                    }

                    // Поиск минимальной площади треугольника
                    if (
                        this.mathematic.GeronLaw(
                            this.InsidePoints[j][i][0], 
                            this.InsidePoints[j][i][1], 
                            this.InsidePoints[j][i][2], 
                            this.multiplier) < this.MinSquare)
                    {
                        this.MinSquare = this.mathematic.GeronLaw(
                            this.InsidePoints[j][i][0], 
                            this.InsidePoints[j][i][1], 
                            this.InsidePoints[j][i][2], 
                            this.multiplier);
                        this.iZoneMinSquare = j;
                    }
                }
            }

            // Поиск треугольников с углами, выходящими за рамки допустимых
            double a, b, c; // Стороны треугольника
            a = this.mathematic.FindDist(this.InsidePoints[0][0][0], this.InsidePoints[0][0][1]);
            b = this.mathematic.FindDist(this.InsidePoints[0][0][1], this.InsidePoints[0][0][2]);
            c = this.mathematic.FindDist(this.InsidePoints[0][0][2], this.InsidePoints[0][0][0]);
            this.MinAngle = this.mathematic.CosineLaw(a, b, c);

            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.InsidePoints[j].Count; i++)
                {
                    a = this.mathematic.FindDist(this.InsidePoints[j][i][0], this.InsidePoints[j][i][1]);
                    b = this.mathematic.FindDist(this.InsidePoints[j][i][1], this.InsidePoints[j][i][2]);
                    c = this.mathematic.FindDist(this.InsidePoints[j][i][2], this.InsidePoints[j][i][0]);
                    if ((this.mathematic.CosineLaw(a, b, c) < this.MinAllowAngle) ||
                        (this.mathematic.CosineLaw(a, b, c) > this.MaxAllowAngle) ||
                        (this.mathematic.CosineLaw(b, c, a) < this.MinAllowAngle) ||
                        (this.mathematic.CosineLaw(b, c, a) > this.MaxAllowAngle) ||
                        (this.mathematic.CosineLaw(c, a, b) < this.MinAllowAngle) ||
                        (this.mathematic.CosineLaw(c, a, b) > this.MaxAllowAngle))
                    {
                        var Angles = new double[3];
                        Angles[0] = this.mathematic.CosineLaw(a, b, c);
                        Angles[1] = this.mathematic.CosineLaw(b, c, a);
                        Angles[2] = this.mathematic.CosineLaw(c, a, b);
                        this.BadAngleNum[j].Add(i);
                        this.BadAngle[j].Add(Angles);
                    }

                    // Поиск минимального угла в сетке КЭ
                    if (this.mathematic.CosineLaw(a, b, c) < this.MinAngle)
                    {
                        this.MinAngle = this.mathematic.CosineLaw(a, b, c);
                        this.iZoneMinAngle = j;
                    }

                    if (this.mathematic.CosineLaw(b, c, a) < this.MinAngle)
                    {
                        this.MinAngle = this.mathematic.CosineLaw(b, c, a);
                        this.iZoneMinAngle = j;
                    }

                    if (this.mathematic.CosineLaw(c, a, b) < this.MinAngle)
                    {
                        this.MinAngle = this.mathematic.CosineLaw(c, a, b);
                        this.iZoneMinAngle = j;
                    }
                }
            }

            this.bShowBedTriangle = true;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The init colors.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void InitColors(bool bDraw)
        {
            // Инициализация цветовой схемы
            if (bDraw)
            {
                this.ZonePen = new Pen(this.ZoneLineColor, 2.0f); // Карандаш для зон
                this.InsidePen = new Pen(this.ZoneLineColor, 1.0f); // Карандаш для внутреннего разбиения зон
                this.InterPointsBrush = new SolidBrush(this.InterPointsColor); // Кисть промежуточных точек зон
                this.ZoneCoordBrush = new SolidBrush(this.ZoneCoordColor); // Кисть для вывода координат узлов зон
                this.ZonePointNumBrush = new SolidBrush(this.ZonePointNumColor); // Кисть для вывода номеров узлов зон
                this.DensityFunctionBrush = new SolidBrush(this.DensityFunctionColor);
                    
                    // Кисть для выделения точек задания функции плотности
            }
        }

        /// <summary>
        /// The image drawing.
        /// </summary>
        private void ImageDrawing()
        {
            // Рисование изображения
            this.InitColors(true);
            this.DrawScale(true);
            this.DrawZonesZonepointsZonenum(true);
            this.ShowBedTriangle(this.bShowBedTriangle);
            this.DrawMesh(this.bDrawMesh);
            this.DrawZonesZonepointsZonenum(true);
            this.DrawZonePointNum(this.bDrawZonePointNum);
            this.DrawZoneCoord(this.bDrawZoneCoord);
            this.DrawDensityFunction(this.bShowDensityFunc);
            this.DrawTriangleNum(this.bDrawTriangleNum);
        }

        /// <summary>
        /// The show bed triangle.
        /// </summary>
        /// <param name="bShow">
        /// The b show.
        /// </param>
        private void ShowBedTriangle(bool bShow)
        {
            // Выделение "плохих" треугольников
            if (!bShow)
            {
                return;
            }

            GraphicsPath gp;
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выделяем треугольники с малой площадью
                for (int i = 0; i < this.BadTrianglesNum[j].Count; i++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.InsidePoints[j][this.BadTrianglesNum[j][i]]);
                    gp.CloseFigure();
                    this.eee.FillPath(this.BadSquareBrush, gp);
                }
            }

            // Выделяем треугольники с углами, выходящими за рамки допустимых
            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.BadAngleNum[j].Count; i++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.InsidePoints[j][this.BadAngleNum[j][i]]);
                    gp.CloseFigure();
                    this.eee.FillPath(this.BadAngleBrush, gp);
                }
            }
        }

        /// <summary>
        /// The draw triangle num.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void DrawTriangleNum(bool bDraw)
        {
            // Вывод номеров треугольников
            if (!bDraw)
            {
                return;
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.InsidePoints[i].Count; j++)
                {
                    this.eee.Transform = new Matrix(
                        1, 0, 0, 1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y);
                    this.eee.TranslateTransform(this.iOffsetXOY, -this.iOffsetXOY);
                    this.eee.DrawString(
                        this.TriangleNum[i][j].ToString(), 
                        this.TriangleNumFont, 
                        Brushes.Brown, 
                        (this.InsidePoints[i][j][0].X + this.InsidePoints[i][j][1].X + this.InsidePoints[i][j][2].X) / 3 -
                        8, 
                        this.pictureBox1.Height -
                        (this.InsidePoints[i][j][0].Y + this.InsidePoints[i][j][1].Y + this.InsidePoints[i][j][2].Y) / 3 -
                        6);
                    this.eee.Transform = new Matrix(
                        1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
                    this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);
                }
            }
        }

        /// <summary>
        /// The draw zone point num.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void DrawZonePointNum(bool bDraw)
        {
            // Вывод номеров узлов зон
            if (!bDraw)
            {
                return;
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    this.eee.Transform = new Matrix(
                        1, 0, 0, 1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y);
                    this.eee.TranslateTransform(this.iOffsetXOY, -this.iOffsetXOY);
                    this.eee.DrawString(
                        this.ZonesPointsNum[j][i].ToString(), 
                        new Font("Arial", 12), 
                        Brushes.Magenta, 
                        this.ZonesPoints[j][i].X - 22, 
                        this.pictureBox1.Height - this.ZonesPoints[j][i].Y - 20);
                    this.eee.Transform = new Matrix(
                        1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
                    this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);
                }
            }
        }

        /// <summary>
        /// The draw zone coord.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void DrawZoneCoord(bool bDraw)
        {
            // Вывод координат узлов зон
            if (!bDraw)
            {
                return;
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    this.eee.Transform = new Matrix(
                        1, 0, 0, 1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y);
                    this.eee.TranslateTransform(this.iOffsetXOY, -this.iOffsetXOY);
                    this.eee.DrawString(
                        " (" + Math.Round(1.0 * this.ZonesPoints[j][i].X / this.multiplier, 2) + ";" +
                        Math.Round(1.0 * this.ZonesPoints[j][i].Y / this.multiplier, 2) + ")", 
                        this.ZoneCoordFont, 
                        this.ZoneCoordBrush, 
                        this.ZonesPoints[j][i].X + 6, 
                        this.pictureBox1.Height - this.ZonesPoints[j][i].Y - 17);
                    this.eee.Transform = new Matrix(
                        1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
                    this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);
                }
            }
        }

        /// <summary>
        /// Рисование делений шкалы
        /// </summary>
        /// <param name="bDraw">
        /// </param>
        private void DrawScale(bool bDraw)
        {
            // Рисование делений шкалы
            if (!bDraw)
            {
                return;
            }

            this.eee.Clear(this.BackGroundColor);

            // Линии сетки
            Point p1, p2;
            for (int i = this.multiplier; i < this.pictureBox1.Width; i = i + this.multiplier)
            {
                p1 = new Point(i - this.iOffsetXOY, -this.iOffsetXOY);
                p2 = new Point(i - this.iOffsetXOY, this.pictureBox1.Height + this.iOffsetXOY);
                this.eee.DrawLine(this.InterDivPen, p1, p2);
            }

            for (int i = this.multiplier; i < this.pictureBox1.Height; i = i + this.multiplier)
            {
                p1 = new Point(-this.iOffsetXOY, i - this.iOffsetXOY);
                p2 = new Point(this.pictureBox1.Width + this.iOffsetXOY, i - this.iOffsetXOY);
                this.eee.DrawLine(this.InterDivPen, p1, p2);
            }

            for (int i = 0; i < this.pictureBox1.Width; i = i + this.multiplier * 10)
            {
                p1 = new Point(i, 0);
                p2 = new Point(i, this.pictureBox1.Height);
                this.eee.DrawLine(this.BaseDivPen, p1, p2);
                this.eee.DrawLine(this.BaseDivPen, i, 0, i, -this.iOffsetXOY);
            }

            for (int i = 0; i < this.pictureBox1.Height; i = i + this.multiplier * 10)
            {
                p1 = new Point(0, i);
                p2 = new Point(this.pictureBox1.Width, i);
                this.eee.DrawLine(this.BaseDivPen, p1, p2);
                this.eee.DrawLine(this.BaseDivPen, -this.iOffsetXOY, i, 0, i);
            }

            this.eee.DrawLine(this.AxesPen, 0, 0, this.pictureBox1.Width, 0); // Координатные оси
            this.eee.DrawLine(this.AxesPen, 0, 0, 0, this.pictureBox1.Height);
        }

        /// <summary>
        /// Рисование зон, основных точек зон
        /// </summary>
        /// <param name="bDraw">
        /// </param>
        private void DrawZonesZonepointsZonenum(bool bDraw)
        {
            // Рисование зон, основных точек зон
            if (!bDraw)
            {
                return;
            }

            this.InitColors(bDraw);

            // ----------- Рисуем зоны  -------------
            for (int j = 0; j < this.cZoneCount; j++)
            {
                this.FrontZone = new GraphicsPath();
                this.FrontZone.StartFigure();
                this.FrontZone.AddLines(this.Front[j]);
                this.FrontZone.CloseFigure();
                this.eee.DrawPath(this.ZonePen, this.FrontZone);
            }

            // -------------- Рисование всех точек на границе зон ---------------
            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.Front[i].Length; j++)
                {
                    this.eee.FillEllipse(
                        this.InterPointsBrush, 
                        this.Front[i][j].X - this.fInterPointSize, 
                        this.Front[i][j].Y - this.fInterPointSize, 
                        this.fPointSize * 2 / 3, 
                        this.fPointSize * 2 / 3);
                }
            }

            float MinX = 0, MaxX = 0, MinY = 0, MaxY = 0, Xz, Yz; // Координаты размещения номера зоны
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                MinX = this.ZonesPoints[j][0].X;
                MaxX = this.ZonesPoints[j][0].X;
                MinY = this.ZonesPoints[j][0].Y;
                MaxY = this.ZonesPoints[j][0].Y;
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    // Поиск минимальной и максимальной координат зон для вывода номера зоны
                    if (this.ZonesPoints[j][i].X < MinX)
                    {
                        MinX = this.ZonesPoints[j][i].X;
                    }

                    if (this.ZonesPoints[j][i].X > MaxX)
                    {
                        MaxX = this.ZonesPoints[j][i].X;
                    }

                    if (this.ZonesPoints[j][i].Y < MinY)
                    {
                        MinY = this.ZonesPoints[j][i].Y;
                    }

                    if (this.ZonesPoints[j][i].Y > MaxY)
                    {
                        MaxY = this.ZonesPoints[j][i].Y;
                    }

                    // ----------- Рисуем узлы зон  -------------
                    this.eee.FillEllipse(
                        this.BasePointsBrush, 
                        this.ZonesPoints[j][i].X - (this.fPointSize / 2), 
                        this.ZonesPoints[j][i].Y - (this.fPointSize / 2), 
                        this.fPointSize, 
                        this.fPointSize);
                }

                // ----------- Выводим номера зон  -------------
                Xz = MinX + 0.5f * (MaxX - MinX);
                Yz = MinY + 0.5f * (MaxY - MinY);

                this.eee.Transform = new Matrix(1, 0, 0, 1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y);
                this.eee.TranslateTransform(this.iOffsetXOY, -this.iOffsetXOY);
                switch (j)
                {
                    case 0:
                        this.eee.DrawString(
                            "I", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 1:
                        this.eee.DrawString(
                            "II", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 2:
                        this.eee.DrawString(
                            "III", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 3:
                        this.eee.DrawString(
                            "IV", this.ZonesFont, Brushes.Green, Xz - 60, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 4:
                        this.eee.DrawString(
                            "V", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 5:
                        this.eee.DrawString(
                            "VI", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 6:
                        this.eee.DrawString(
                            "VII", this.ZonesFont, Brushes.Green, Xz - 30, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 7:
                        this.eee.DrawString(
                            "VIII", this.ZonesFont, Brushes.Green, Xz - 40, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 8:
                        this.eee.DrawString(
                            "IX", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 9:
                        this.eee.DrawString(
                            "X", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 10:
                        this.eee.DrawString(
                            "XI", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 11:
                        this.eee.DrawString(
                            "XII", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 12:
                        this.eee.DrawString(
                            "XIII", this.ZonesFont, Brushes.Green, Xz - 40, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 13:
                        this.eee.DrawString(
                            "XIV", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 14:
                        this.eee.DrawString(
                            "XV", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 15:
                        this.eee.DrawString(
                            "XVI", this.ZonesFont, Brushes.Green, Xz - 30, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 16:
                        this.eee.DrawString(
                            "XVII", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 17:
                        this.eee.DrawString(
                            "XVIII", this.ZonesFont, Brushes.Green, Xz - 50, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 18:
                        this.eee.DrawString(
                            "XIX", this.ZonesFont, Brushes.Green, Xz - 40, this.pictureBox1.Height - Yz - 20);
                        break;
                    case 19:
                        this.eee.DrawString(
                            "XX", this.ZonesFont, Brushes.Green, Xz - 20, this.pictureBox1.Height - Yz - 20);
                        break;
                }

                this.eee.Transform = new Matrix(
                    1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
                this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);
            }
        }

        /// <summary>
        /// The draw mesh.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void DrawMesh(bool bDraw)
        {
            // Рисование сетки КЭ
            if (!bDraw)
            {
                return;
            }

            GraphicsPath gp;
            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.InsidePoints[i].Count; j++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.InsidePoints[i][j]);
                    gp.CloseFigure();
                    this.eee.DrawPath(this.InsidePen, gp);
                }
            }
        }

        /// <summary>
        /// The draw density function.
        /// </summary>
        /// <param name="bDraw">
        /// The b draw.
        /// </param>
        private void DrawDensityFunction(bool bDraw)
        {
            // Рисование функции плотности
            if (!bDraw)
            {
                return;
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.DensityPoints[i].Count; j++)
                {
                    this.eee.FillEllipse(
                        this.DensityFunctionBrush, 
                        this.DensityPoints[i][j].X - this.fInterPointSize, 
                        this.DensityPoints[i][j].Y - this.fInterPointSize, 
                        this.fPointSize * 2 / 3, 
                        this.fPointSize * 2 / 3);
                    this.eee.Transform = new Matrix(
                        1, 0, 0, 1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y);
                    this.eee.TranslateTransform(this.iOffsetXOY, -this.iOffsetXOY);
                    this.eee.DrawString(
                        this.DensityValues[i][j].ToString(), 
                        this.DensityFunctionFont, 
                        this.DensityFunctionBrush, 
                        this.DensityPoints[i][j].X + 6, 
                        this.pictureBox1.Height - this.DensityPoints[i][j].Y - 17);
                    this.eee.Transform = new Matrix(
                        1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
                    this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);
                }
            }
        }

        /// <summary>
        /// The show tool tip.
        /// </summary>
        /// <param name="p">
        /// The p.
        /// </param>
        private void ShowToolTip(Point p)
        {
            // Отобразить параметры треугольника
            if (!this.bShowBedTriangle)
            {
                return; // Если "плохие" треугольники не определены, выход
            }

            var p2 = new Point(p.X - this.iOffsetXOY, this.pictureBox1.Height - p.Y - this.iOffsetXOY);
            GraphicsPath gp;

            // Поиск "плохих" углов
            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.BadAngle[j].Count; i++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.InsidePoints[j][this.BadAngleNum[j][i]]);
                    gp.CloseFigure();
                    if (gp.IsVisible(p2))
                    {
                        this.toolTip1.Active = true;
                        this.toolTip1.Show(
                            "α1 = " + Math.Round(this.BadAngle[j][i][0], 2) + "°; α2 = " +
                            Math.Round(this.BadAngle[j][i][1], 2) + "°; α3 = " + Math.Round(this.BadAngle[j][i][2], 2) +
                            "°;", 
                            this.pictureBox1, 
                            p);
                        return;
                    }
                }
            }

            // Поиск "плохих" площадей
            for (int j = 0; j < this.cZoneCount; j++)
            {
                for (int i = 0; i < this.BadTrianglesNum[j].Count; i++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.InsidePoints[j][this.BadTrianglesNum[j][i]]);
                    gp.CloseFigure();
                    if (gp.IsVisible(p2))
                    {
                        this.toolTip1.Active = true;
                        this.toolTip1.Show(
                            "S = " +
                            Math.Round(
                                this.mathematic.GeronLaw(
                                    this.InsidePoints[j][this.BadTrianglesNum[j][i]][0], 
                                    this.InsidePoints[j][this.BadTrianglesNum[j][i]][1], 
                                    this.InsidePoints[j][this.BadTrianglesNum[j][i]][2], 
                                    this.multiplier), 
                                2), 
                            this.pictureBox1, 
                            p);
                        return;
                    }
                }
            }

            this.toolTip1.Active = false;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The form 1_ load.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void Form1_Load(object sender, EventArgs e)
        {
            // Загрузка формы
            this.provider.NumberDecimalSeparator = ".";
            this.pAllocation = new Point(-1000, -1000);
            this.sts = new Settings();
            this.tstpt = new TestPlate();
            this.tstres = new TestResult();
            this.err = new ErrorMessage();
            this.Init();
            if (this.iMeshCriterion == 4)
            {
                this.buttonSetXY.Enabled = true;
                this.bShowDensityFunc = true;
            }
            else
            {
                this.buttonSetXY.Enabled = false;
                this.bShowDensityFunc = false;
            }

            this.MeshStep = Convert.ToSingle(this.textBoxStepSize.Text, this.provider) * this.multiplier;

            this.fInterPointSize = this.fPointSize / 3.0f; // Размер промежуточных точек

            this.InterDivPen = new Pen(this.InterDivColor, 0.5f); // Карандаш для промежуточных делений шкалы
            this.BaseDivPen = new Pen(this.BaseDivColor, 1.5f); // Карандаш для основных делений шкалы
            this.AxesPen = new Pen(this.AxesColor, 2.1f); // Карандаш для осей XOY
            this.BasePointsBrush = new SolidBrush(this.BasePointsColor); // Кисть основных точек зон
            this.BackGroundBrush = new SolidBrush(this.BackGroundColor); // Кисть для фона
            this.ZonePointNumBrush = new SolidBrush(this.ZonePointNumColor); // Кисть для номеров узлов зон
            this.BadSquareBrush = new SolidBrush(this.BadSquareColor);
                
                // Кисть выделения треугольников с малой площадью
            this.BadAngleBrush = new SolidBrush(this.BadAngleColor);
                
                // Кисть выделения треугольников с "плохими" углами
            this.DensityFunctionBrush = new SolidBrush(this.DensityFunctionColor);
                
                // Кисть для выделения точек задания функции плотности
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>(1);
            }

            this.AllPoints = new List<Point>[this.cZoneCount]; // Инициализация списка узлов
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.AllPoints[i] = new List<Point>(1);
            }

            this.AllPointsArray = new List<Point>(1);
            this.AllPointsNum = new List<int>(1);
            this.AllElem = new List<Point[]>(1);
            this.TriangleNum = new int[this.cZoneCount][]; // Инициализация массива номеров КЭ
            this.DensityPoints = new List<Point>[this.cZoneCount];
                
                // Инициализация точек задания функции плотности для каждой зоны
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.DensityPoints[i] = new List<Point>(1);
            }

            this.DensityValues = new List<double>[this.cZoneCount];
                
                // Инициализация значений функции плотности в заданных точках
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.DensityValues[i] = new List<double>(1);
            }

            this.eee = this.pictureBox1.CreateGraphics();
            this.eee.SmoothingMode = SmoothingMode.AntiAlias;
            this.eee.Transform = new Matrix(
                1, 0, 0, -1, this.pictureBox1.Location.X, this.pictureBox1.Location.Y + this.pictureBox1.Height);
            this.eee.TranslateTransform(this.iOffsetXOY, this.iOffsetXOY);

            this.iTimer3 = 0;
            this.timer3.Enabled = true;
            this.timer3.Start();
        }

        /// <summary>
        /// The button 2_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button2_Click(object sender, EventArgs e)
        {
            // Построение сетки КЭ
            this.textBoxFxy.Enabled = false;
            this.buttonSetXY.BackColor = this.BackAddDelColor;
            this.bShowBedTriangle = false;
            this.button5.BackColor = this.BackAddDelColor;
            this.button6.BackColor = this.BackAddDelColor;
            this.buttonSetXY.BackColor = this.BackAddDelColor;
            this.bAdd = false;
            this.bDelete = false;
            this.bDrawMesh = true;
            this.DrawScale(true);
            this.DrawZonesZonepointsZonenum(true);
            this.button7.Enabled = false;
            this.button9.Enabled = false;
            this.buttonBuildFrontal.Enabled = false;
            this.buttonDelete.Enabled = false;
            this.buttonRegularization.Enabled = false;
            this.buttonSetStep.Enabled = false;
            this.button5.Enabled = false;
            this.button6.Enabled = false;
            this.buttonDelone.Enabled = false;
            this.hScrollBarSpeed.Enabled = false;
            this.checkBox1.Enabled = false;
            this.checkBox2.Enabled = false;
            this.checkBox3.Enabled = false;
            this.checkBox4.Enabled = false;
            this.timeStart.Reset();
            this.timeStart.Start();
            this.Mesh();
            this.timeStart.Stop();
            if (this.bError)
            {
                this.err.label1.Text = "Невозможно построить сетку КЭ при заданных параметрах.";
                this.err.ShowDialog();
                this.bError = false;
            }

            this.DrawZonesZonepointsZonenum(true);
            this.DrawZonePointNum(this.bDrawZonePointNum);
            this.DrawZoneCoord(this.bDrawZoneCoord);
            this.DrawDensityFunction(this.bDensityFunction);
            this.DrawTriangleNum(this.bDrawTriangleNum);
            this.button7.Enabled = true;
            this.button9.Enabled = true;
            this.buttonBuildFrontal.Enabled = true;
            this.buttonDelete.Enabled = true;
            this.buttonRegularization.Enabled = true;
            this.buttonSetStep.Enabled = true;
            this.button5.Enabled = true;
            this.button6.Enabled = true;
            this.buttonDelone.Enabled = true;
            this.hScrollBarSpeed.Enabled = true;
            this.checkBox1.Enabled = true;
            this.checkBox2.Enabled = true;
            this.checkBox3.Enabled = true;
            this.checkBox4.Enabled = true;
        }

        /// <summary>
        /// The picture box 1_ mouse move.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            this.toolStripStatusLabel1.Text = " X = " + Math.Round(1.0 * (e.X - this.iOffsetXOY) / this.multiplier, 2) +
                                              "   Y = " +
                                              Math.Round(
                                                  1.0 * (this.pictureBox1.Height - e.Y - this.iOffsetXOY) /
                                                   this.multiplier, 
                                                  2);

            if (!this.bAllocation)
            {
                this.textBox2.Text = Math.Round(1.0 * (e.X - this.iOffsetXOY) / this.multiplier, 2).ToString();
                this.textBox3.Text =
                    Math.Round(1.0 * (this.pictureBox1.Height - e.Y - this.iOffsetXOY) / this.multiplier, 2).ToString(
                        );
            }

            double Dist;
            var p = new Point(e.X - this.iOffsetXOY, this.pictureBox1.Height - e.Y - this.iOffsetXOY);
            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                for (int i = 0; i < this.cPointsInZone; i++)
                {
                    Dist = this.mathematic.FindDist(p, this.ZonesPoints[j][i]);
                    if (Dist <= 1.5f * this.fPointSize)
                    {
                        this.eee.FillEllipse(
                            this.InterPointsBrush, 
                            this.ZonesPoints[j][i].X - (this.fPointSize / 2), 
                            this.ZonesPoints[j][i].Y - (this.fPointSize / 2), 
                            this.fPointSize, 
                            this.fPointSize);
                    }
                    else if (this.bAllocation && (this.ZonesPoints[j][i] == this.pAllocation))
                    {
                        // Заливаем выделенный узел
                        this.eee.FillEllipse(
                            this.InterPointsBrush, 
                            this.pAllocation.X - (this.fPointSize / 2), 
                            this.pAllocation.Y - (this.fPointSize / 2), 
                            this.fPointSize, 
                            this.fPointSize);
                    }
                    else
                    {
                        this.eee.FillEllipse(
                            this.BasePointsBrush, 
                            this.ZonesPoints[j][i].X - (this.fPointSize / 2), 
                            this.ZonesPoints[j][i].Y - (this.fPointSize / 2), 
                            this.fPointSize, 
                            this.fPointSize);
                    }
                }
            }

            this.ttPoint = new Point(e.X, e.Y); // Точка для вывода tooltip
        }

        /// <summary>
        /// The button 1_ click_1.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button1_Click_1(object sender, EventArgs e)
        {
            // Удаление сетки КЭ
            this.bError = false;
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            this.DensityPoints = new List<Point>[this.cZoneCount];
                
                // Инициализация точек задания функции плотности для каждой зоны
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.DensityPoints[i] = new List<Point>(1);
            }

            this.DensityValues = new List<double>[this.cZoneCount];
                
                // Инициализация значений функции плотности в заданных точках
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.DensityValues[i] = new List<double>(1);
            }

            this.textBoxFxy.Enabled = false;
            this.buttonSetXY.BackColor = this.BackAddDelColor;
            this.bDensityFunction = false;
            this.bDrawMesh = false;
            this.bShowBedTriangle = false;
            this.bShowDensityFunc = false;
            this.ImageDrawing();

            this.button5.BackColor = this.BackAddDelColor;
            this.button6.BackColor = this.BackAddDelColor;
            this.buttonSetXY.BackColor = this.BackAddDelColor;
            this.buttonRegularization.Enabled = false;
            this.button9.Enabled = false;
            this.bAdd = false;
            this.bDelete = false;
        }

        /// <summary>
        /// The button 3_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button3_Click(object sender, EventArgs e)
        {
            // Задать шаг первичного разбиения сторон зон
            this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.bShowBedTriangle = false;
            this.bDrawMesh = false;
            this.ImageDrawing();

            this.button5.BackColor = this.BackAddDelColor;
            this.button6.BackColor = this.BackAddDelColor;
            this.button9.Enabled = false;
            this.bAdd = false;
            this.bDelete = false;
            this.textBoxStepSize.Enabled = true;
            this.buttonOk.Visible = true;
            this.buttonRegularization.Enabled = false;
            this.textBox2.Enabled = false;
            this.textBox3.Enabled = false;
        }

        /// <summary>
        /// The button 4_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button4_Click(object sender, EventArgs e)
        {
            // Подтверждение первичного разбиения сторон зон
            this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.bShowBedTriangle = false;
            if (Convert.ToSingle(this.textBoxStepSize.Text, this.provider) < 0.5f)
            {
                this.textBoxStepSize.Text = "0.5";
            }

            this.MeshStep = Convert.ToSingle(this.textBoxStepSize.Text, this.provider) * this.multiplier;
            this.EqualMesh(this.MeshStep);
            this.bDrawMesh = false;
            this.ImageDrawing();
            this.textBoxStepSize.Enabled = false;
            this.buttonOk.Visible = false;
            this.buttonRegularization.Enabled = false;
            this.button9.Enabled = false;
        }

        /// <summary>
        /// The button 5_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button5_Click(object sender, EventArgs e)
        {
            // Добавить узлы
            this.bShowBedTriangle = false;
            this.buttonRegularization.Enabled = false;
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            if (!this.bAdd)
            {
                this.bDrawMesh = false;
                this.ImageDrawing();

                this.button5.BackColor = this.AllocColor;
                this.button6.BackColor = this.BackAddDelColor;
                this.bAdd = true;
                this.bDelete = false;
                this.textBoxStepSize.Enabled = false;
                this.buttonOk.Visible = false;
                this.button9.Enabled = false;
            }
            else
            {
                this.button5.BackColor = this.BackAddDelColor;
                this.bAdd = false;
            }
        }

        /// <summary>
        /// The button 6_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button6_Click(object sender, EventArgs e)
        {
            // Удалить узлы
            this.bShowBedTriangle = false;
            this.buttonRegularization.Enabled = false;
            this.button9.Enabled = false;
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            if (!this.bDelete)
            {
                this.bDrawMesh = false;
                this.ImageDrawing();

                this.button6.BackColor = this.AllocColor;
                this.button5.BackColor = this.BackAddDelColor;
                this.bAdd = false;
                this.bDelete = true;
                this.textBoxStepSize.Enabled = false;
                this.buttonOk.Visible = false;
            }
            else
            {
                this.button6.BackColor = this.BackAddDelColor;
                this.bDelete = false;
            }
        }

        /// <summary>
        /// The picture box 1_ mouse click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
        {
            // Добавление/удаление/выделение узлов/задание функции плотности
            this.bShowBedTriangle = false;
            var p = new Point(e.X - this.iOffsetXOY, this.pictureBox1.Height - e.Y - this.iOffsetXOY);

            Point lp1 = new Point(), lp2 = new Point();
                
                // точки зоны, составляющие сторону с мин.расстоянием до новой точки
            Point lp21 = new Point(), lp22 = new Point();
                
                // точки зоны, составляющие сторону с мин.расстоянием до новой точки
            double MinDist = 100;
            double TempDist;
            Point p1, p2;
            int z1 = -1, z2 = -1;

            if (this.bAdd)
            {
                // Добавление узлов
                bool bCircle = false; // Признак, лежит ли точка на дуге
                for (int j = 0; j < this.cZoneCount; j++)
                {
                    // Выполняем цикл для каждой зоны
                    for (int i = 0; i < this.cPointsInZone; i++)
                    {
                        // И для каждой точки
                        p1 = this.ZonesPoints[j][i];
                        if (i == this.cPointsInZone - 1)
                        {
                            p2 = this.ZonesPoints[j][0];
                        }
                        else
                        {
                            p2 = this.ZonesPoints[j][i + 1];
                        }

                        TempDist = this.mathematic.FindDistPoint2Line(p, p1, p2);
                        if (TempDist <= MinDist + 0.0001f)
                        {
                            if (
                                !this.mathematic.NearPoint(
                                    this.mathematic.FindDist(p1, p), 
                                    this.mathematic.FindDist(p2, p), 
                                    TempDist, 
                                    this.mathematic.FindDist(p1, p2)))
                            {
                                continue;
                            }

                            if (TempDist < MinDist - 0.0001f)
                            {
                                MinDist = TempDist;
                                z1 = j;
                                lp1 = p1;
                                lp2 = p2;
                            }
                            else if ((TempDist < MinDist + 0.0001f) && (TempDist > MinDist - 0.0001f))
                            {
                                z2 = j;
                                lp21 = p1;
                                lp22 = p2;
                            }
                        }
                    }
                }

                ///////////////////////  Добавляем точку /////////////////////////////////////////
                var newPoint = new Point();
                double l1 =
                    Math.Sqrt(this.mathematic.FindDist(lp1, p) * this.mathematic.FindDist(lp1, p) - MinDist * MinDist);
                newPoint.X = (int)Math.Round(l1 * (lp2.X - lp1.X) / this.mathematic.FindDist(lp1, lp2) + lp1.X);
                newPoint.Y = (int)Math.Round(l1 * (lp2.Y - lp1.Y) / this.mathematic.FindDist(lp1, lp2) + lp1.Y);

                // Проверяем, лежит ли точка на дуге
                int iii = 0;
                var pO = new Point(); // Координаты центра окружности
                for (int j = 0; j < this.RoundingPoints.Count; j++)
                {
                    if ((lp1 == this.RoundingPoints[j][0]) || (lp1 == this.RoundingPoints[j][1]) ||
                        (lp1 == this.RoundingPoints[j][2]))
                    {
                        iii++;
                        pO = this.CircleCenters[j];
                        break;
                    }
                }

                for (int j = 0; j < this.RoundingPoints.Count; j++)
                {
                    if ((lp2 == this.RoundingPoints[j][0]) || (lp2 == this.RoundingPoints[j][1]) ||
                        (lp2 == this.RoundingPoints[j][2]))
                    {
                        iii++;
                        break;
                    }
                }

                if (iii == 2)
                {
                    // Если точка лежит на дуге, корректируем её координаты
                    bCircle = true;
                    double alpha, a;
                    alpha = this.mathematic.CosineLaw(
                        this.mathematic.FindDist(lp1, newPoint), 
                        this.mathematic.FindDist(pO, lp1), 
                        this.mathematic.FindDist(pO, newPoint));
                    a = this.mathematic.CosineLaw2(alpha, this.fRoundingRadius, this.fRoundingRadius);
                    newPoint = this.mathematic.FindPointOnCircle(pO, lp1, this.fRoundingRadius, a, lp2);
                }

                this.AddPaintPoint(MinDist, newPoint, z1, lp1, lp2, bCircle);
                if (z2 >= 0)
                {
                    this.AddPaintPoint(MinDist, newPoint, z2, lp21, lp22, bCircle);
                }

                if (bCircle)
                {
                    this.ImageDrawing();
                }
            }
            else if (this.bDelete)
            {
                // Удаление узлов
                // Удаляем точку   ///////////////////////////////////////////////////
                var pmin = new Point(); // Координа точки, ближайшей к точке нажатия
                double dMin = 1000; // Минимальное расстояние между точкой нажатия и точкой фронта
                for (int i = 0; i < this.cZoneCount; i++)
                {
                    for (int j = 0; j < this.Front[i].Length; j++)
                    {
                        if (this.mathematic.FindDist(this.Front[i][j], p) < dMin)
                        {
                            dMin = this.mathematic.FindDist(this.Front[i][j], p);
                            pmin = this.Front[i][j];
                        }
                    }
                }

                for (int i = 0; i < this.cZoneCount; i++)
                {
                    // Ищем точку среди основных точек зон
                    for (int j = 0; j < this.cPointsInZone; j++)
                    {
                        if (this.ZonesPoints[i][j] == pmin)
                        {
                            return;
                        }
                    }
                }

                if (dMin < this.fPointSize * 1.5f)
                {
                    // Иначе удаляем
                    for (int i = 0; i < this.cZoneCount; i++)
                    {
                        for (int j = 0; j < this.Front[i].Length; j++)
                        {
                            if (this.Front[i][j] == pmin)
                            {
                                this.TempFront = new Point[this.Front[i].Length];
                                for (int k = 0; k < this.Front[i].Length; k++)
                                {
                                    this.TempFront[k] = this.Front[i][k];
                                }

                                this.Front[i] = new Point[this.TempFront.Length - 1];

                                for (int k = 0; k < j; k++)
                                {
                                    // Копируем новый фронт
                                    this.Front[i][k] = this.TempFront[k];
                                }

                                for (int k = j + 1; k < this.TempFront.Length; k++)
                                {
                                    this.Front[i][k - 1] = this.TempFront[k];
                                }
                            }
                        }
                    }

                    // Перерисовываем область
                    this.ImageDrawing();
                }
            }
            else if (this.bDensityFunction)
            {
                // Задание функции плотности
                if (this.curZoneDensity > -1)
                {
                    if (this.textBoxFxy.Text != string.Empty)
                    {
                        if (this.bOldPoint)
                        {
                            // Если изменяется величина функции плотности
                            if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) >= 20)
                            {
                                this.textBoxFxy.Text = "20";
                            }
                            else if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) <= 0.1)
                            {
                                this.textBoxFxy.Text = "0.1";
                            }

                            this.DensityValues[this.curZoneDensity][this.iOldPoint] =
                                Math.Round(Convert.ToSingle(this.textBoxFxy.Text, this.provider), 2);
                            this.eee.FillEllipse(
                                this.DensityFunctionBrush, 
                                this.DensityPoints[this.curZoneDensity][this.iOldPoint].X - this.fInterPointSize, 
                                this.DensityPoints[this.curZoneDensity][this.iOldPoint].Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            this.bOldPoint = false;
                            this.ImageDrawing();
                        }
                        else
                        {
                            this.DensityPoints[this.curZoneDensity].Add(this.curDensityFunc);
                            if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) >= 20)
                            {
                                this.textBoxFxy.Text = "20";
                            }
                            else if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) <= 0.1)
                            {
                                this.textBoxFxy.Text = "0.1";
                            }

                            this.DensityValues[this.curZoneDensity].Add(
                                Math.Round(Convert.ToSingle(this.textBoxFxy.Text, this.provider), 2));
                            this.eee.FillEllipse(
                                this.DensityFunctionBrush, 
                                this.curDensityFunc.X - this.fInterPointSize, 
                                this.curDensityFunc.Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                        }

                        this.DrawDensityFunction(true);
                        this.curZoneDensity = -1;
                    }
                    else
                    {
                        // Удаляем точку, если не задана величина
                        if (this.bOldPoint)
                        {
                            this.DensityPoints[this.curZoneDensity].RemoveAt(this.iOldPoint);
                            this.DensityValues[this.curZoneDensity].RemoveAt(this.iOldPoint);
                        }
                    }

                    this.ImageDrawing();
                }

                GraphicsPath gp;
                double Dist = 1000; // Расстояние до ближайшей точки с заданной функцией плотности
                int iNum = -1; // Номер ближайшей точки с заданной функцией плотности
                for (int i = 0; i < this.cZoneCount; i++)
                {
                    gp = new GraphicsPath();
                    gp.StartFigure();
                    gp.AddLines(this.ZonesPoints[i]);
                    gp.CloseFigure();
                    if (gp.IsVisible(p))
                    {
                        // Найдём точку с заданной функцией плотности, ближайшую к выбранной
                        for (int j = 0; j < this.DensityPoints[i].Count; j++)
                        {
                            if (this.mathematic.FindDist(p, this.DensityPoints[i][j]) < Dist)
                            {
                                Dist = this.mathematic.FindDist(p, this.DensityPoints[i][j]);
                                iNum = j;
                            }
                        }

                        if (Dist > 15)
                        {
                            this.eee.FillEllipse(
                                this.InterPointsBrush, 
                                p.X - this.fInterPointSize, 
                                p.Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            this.curDensityFunc = p;
                            this.curZoneDensity = i;
                        }
                        else
                        {
                            this.eee.FillEllipse(
                                this.InterPointsBrush, 
                                this.DensityPoints[i][iNum].X - this.fInterPointSize, 
                                this.DensityPoints[i][iNum].Y - this.fInterPointSize, 
                                this.fPointSize * 2 / 3, 
                                this.fPointSize * 2 / 3);
                            this.bOldPoint = true;
                            this.iOldPoint = iNum;
                            this.curZoneDensity = i;
                        }

                        this.textBoxFxy.Enabled = true;
                        this.textBoxFxy.Select();
                        break;
                    }
                }
            }
            else
            {
                // Проверяем на близость точек для изменения координат
                if (this.bAllocation)
                {
                    for (int i = 0; i < this.cZoneCount; i++)
                    {
                        for (int j = 0; j < this.cPointsInZone; j++)
                        {
                            if (this.ZonesPoints[i][j] == this.pAllocation)
                            {
                                this.ZonesPoints[i][j].X =
                                    (int)
                                    Math.Round(Convert.ToSingle(this.textBox2.Text, this.provider) * this.multiplier);
                                this.ZonesPoints[i][j].Y =
                                    (int)
                                    Math.Round(Convert.ToSingle(this.textBox3.Text, this.provider) * this.multiplier);
                            }
                        }
                    }

                    this.pAllocation.X =
                        (int)Math.Round(Convert.ToSingle(this.textBox2.Text, this.provider) * this.multiplier);
                    this.pAllocation.Y =
                        (int)Math.Round(Convert.ToSingle(this.textBox3.Text, this.provider) * this.multiplier);

                    this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
                    for (int i = 0; i < this.cZoneCount; i++)
                    {
                        this.Front[i] = new Point[this.cPointsInZone];
                    }

                    for (int i = 0; i < this.cZoneCount; i++)
                    {
                        for (int j = 0; j < this.cPointsInZone; j++)
                        {
                            this.Front[i][j] = this.ZonesPoints[i][j];
                        }
                    }

                    this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

                    for (int i = 0; i < this.cZoneCount; i++)
                    {
                        // Инициализация списка треугольников
                        this.InsidePoints[i] = new List<Point[]>();
                    }

                    this.ImageDrawing();
                }

                double dMin = 1000;
                for (int i = 0; i < this.cZoneCount; i++)
                {
                    // Найдём точку, ближайшую к точке нажатия
                    for (int j = 0; j < this.cPointsInZone; j++)
                    {
                        if (this.mathematic.FindDist(p, this.ZonesPoints[i][j]) < dMin)
                        {
                            dMin = this.mathematic.FindDist(p, this.ZonesPoints[i][j]);
                            if (dMin < 1.5 * this.fPointSize)
                            {
                                this.pAllocation = this.ZonesPoints[i][j];
                            }
                        }
                    }
                }

                if (dMin < 1.5 * this.fPointSize)
                {
                    this.bAllocation = true;
                    this.textBox2.Enabled = true;
                    this.textBox3.Enabled = true;
                    this.textBox2.Text = (this.pAllocation.X / this.multiplier).ToString();
                    this.textBox3.Text = (this.pAllocation.Y / this.multiplier).ToString();
                }
                else
                {
                    this.bAllocation = false;
                    this.textBox2.Enabled = false;
                    this.textBox3.Enabled = false;
                }
            }
        }

        /// <summary>
        /// The check box 1_ checked changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            // Отображение номеров КЭ
            if (this.checkBox1.Checked == false)
            {
                this.bDrawTriangleNum = false;
            }
            else
            {
                this.bDrawTriangleNum = true;
                this.DrawTriangleNum(this.bDrawTriangleNum);
            }

            this.ImageDrawing();
        }

        /// <summary>
        /// The button 8_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button8_Click(object sender, EventArgs e)
        {
            // Сохранить и выйти
            this.WriteIniFile(); // Внесение изменений в ini-файл
            this.CreateOutFile();
            this.Close();
        }

        /// <summary>
        /// The text box 2_ leave.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox2_Leave(object sender, EventArgs e)
        {
            // Изменение координаты X узла
            this.bShowBedTriangle = false;

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    if (this.ZonesPoints[i][j] == this.pAllocation)
                    {
                        this.ZonesPoints[i][j].X =
                            (int)Math.Round(Convert.ToSingle(this.textBox2.Text, this.provider) * this.multiplier);
                    }
                }
            }

            this.pAllocation.X = (int)Math.Round(Convert.ToSingle(this.textBox2.Text, this.provider) * this.multiplier);

            this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.ImageDrawing();

            this.eee.FillEllipse(
                this.InterPointsBrush, 
                this.pAllocation.X - (this.fPointSize / 2), 
                this.pAllocation.Y - (this.fPointSize / 2), 
                this.fPointSize, 
                this.fPointSize);
        }

        /// <summary>
        /// The text box 3_ leave.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox3_Leave(object sender, EventArgs e)
        {
            // Изменение координаты Y узла
            this.bShowBedTriangle = false;

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    if (this.ZonesPoints[i][j] == this.pAllocation)
                    {
                        this.ZonesPoints[i][j].Y =
                            (int)Math.Round(Convert.ToSingle(this.textBox3.Text, this.provider) * this.multiplier);
                    }
                }
            }

            this.pAllocation.Y = (int)Math.Round(Convert.ToSingle(this.textBox3.Text, this.provider) * this.multiplier);

            this.Front = new Point[this.cZoneCount][]; // Восстанавливаем фронт по основным точкам зон
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.Front[i] = new Point[this.cPointsInZone];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.cPointsInZone; j++)
                {
                    this.Front[i][j] = this.ZonesPoints[i][j];
                }
            }

            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            for (int i = 0; i < this.cZoneCount; i++)
            {
                // Инициализация списка треугольников
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.ImageDrawing();

            this.eee.FillEllipse(
                this.InterPointsBrush, 
                this.pAllocation.X - (this.fPointSize / 2), 
                this.pAllocation.Y - (this.fPointSize / 2), 
                this.fPointSize, 
                this.fPointSize);
        }

        /// <summary>
        /// The button 7_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button7_Click(object sender, EventArgs e)
        {
            // Настройка
            this.sts.ShowDialog();
            if (this.sts.DialogResult == DialogResult.OK)
            {
                this.bShowDensityFunc = false;
                this.buttonSetXY.Enabled = false;
                if (this.sts.radioButton1.Checked)
                {
                    this.iMeshCriterion = 0;
                }
                else if (this.sts.radioButton2.Checked)
                {
                    this.iMeshCriterion = 1;
                }
                else if (this.sts.radioButton3.Checked)
                {
                    this.iMeshCriterion = 2;
                }
                else if (this.sts.radioButton4.Checked)
                {
                    this.iMeshCriterion = 3;
                }
                else if (this.sts.radioButton5.Checked)
                {
                    this.iMeshCriterion = 4;
                    this.bShowDensityFunc = true;
                    this.buttonSetXY.Enabled = true;
                }

                this.AvgDensityFunction = Convert.ToSingle(this.sts.textBox2.Text, this.provider);
                this.fMiterAngle = Convert.ToInt32(this.sts.textBox1.Text);
                this.ImageDrawing();
            }
        }

        /// <summary>
        /// The button 9_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button9_Click(object sender, EventArgs e)
        {
            // Тест сетки
            this.tstpt.ShowDialog();
            if (this.tstpt.DialogResult == DialogResult.OK)
            {
                this.MinAllowAngle = Convert.ToDouble(this.tstpt.numericUpDown1.Value);
                this.MaxAllowAngle = Convert.ToDouble(this.tstpt.numericUpDown2.Value);
                this.MinAllowSquare = Convert.ToDouble(this.tstpt.textBox3.Text, this.provider);

                if (!this.tstpt.checkBox3.Checked)
                {
                    this.BadAngleBrush = this.BadSquareBrush;
                }
                else
                {
                    this.BadAngleBrush = new SolidBrush(this.BadAngleColor);
                }

                this.TestFiniteElementMesh();

                if (this.tstpt.checkBox1.Checked)
                {
                    this.tstres.listBox1.Items.Clear();
                    for (int j = 0; j < this.cZoneCount; j++)
                    {
                        this.tstres.listBox1.Items.Add("Зона " + (j + 1) + ":");
                        this.tstres.listBox1.Items.Add(
                            "Количество КЭ с малыми площадями - " + this.BadTrianglesNum[j].Count);
                        this.tstres.listBox1.Items.Add("Количество КЭ с малыми углами - " + this.BadAngleNum[j].Count);
                    }

                    this.tstres.listBox1.Items.Add(string.Empty);
                    this.tstres.listBox1.Items.Add(
                        "-----------------------------------------------------------------------");
                    this.tstres.listBox1.Items.Add(
                        "Минимальный угол = " + Math.Round(this.MinAngle, 2) + "° в зоне №" + (this.iZoneMinAngle + 1));
                    this.tstres.listBox1.Items.Add(
                        "Минимальная площадь = " + Math.Round(this.MinSquare, 2) + " в зоне №" +
                        (this.iZoneMinSquare + 1));
                    this.tstres.listBox1.Items.Add(string.Empty);
                    this.tstres.ShowDialog();
                }

                this.checkBox4.Checked = true;
            }

            this.ImageDrawing();
        }

        /// <summary>
        /// The button 10_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button10_Click(object sender, EventArgs e)
        {
            // Регуляризация
            this.bShowBedTriangle = false;
            this.timeStart.Start();
            for (int i = 0; i < 5; i++)
            {
                this.Regularization();
            }

            this.timeStart.Stop();

            MessageBox.Show(string.Format("Time:{0}", this.timeStart.ElapsedMilliseconds));

            this.ImageDrawing();

            // this.AnalyzingFrontalMethod();
        }

        /// <summary>
        /// The check box 2_ checked changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            // Выводить номера узлов зон
            if (this.checkBox2.Checked == false)
            {
                this.bDrawZonePointNum = false;
            }
            else
            {
                this.bDrawZonePointNum = true;
                this.DrawZonePointNum(this.bDrawZonePointNum);
            }

            this.ImageDrawing();
        }

        /// <summary>
        /// The check box 3_ checked changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            // Выводить координаты узлов
            if (this.checkBox3.Checked == false)
            {
                this.bDrawZoneCoord = false;
            }
            else
            {
                this.bDrawZoneCoord = true;
                this.DrawZoneCoord(this.bDrawZoneCoord);
            }

            this.ImageDrawing();
        }

        /// <summary>
        /// The check box 4_ checked changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {
            // Выделять "плохие" КЭ
            if (this.checkBox4.Checked == false)
            {
                this.bShowBedTriangle = false;
            }
            else
            {
                this.bShowBedTriangle = true;
            }

            this.ImageDrawing();
        }

        /// <summary>
        /// The timer 1_ tick.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            // Таймер для вывода параметров КЭ
            if (this.ttPre != this.ttPoint)
            {
                this.ShowToolTip(this.ttPoint);
                if (this.toolTip1.Active)
                {
                    this.ImageDrawing();
                }

                this.ttPre = this.ttPoint;
            }
        }

        /// <summary>
        /// The text box 1_ text changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string text = string.Empty;
            for (int i = 0; i < this.textBoxStepSize.Text.Length - 1; i++)
            {
                text += this.textBoxStepSize.Text[i];
            }

            if (this.textBoxStepSize.Text.Length >= 1)
            {
                if (
                    !((this.textBoxStepSize.Text[this.textBoxStepSize.Text.Length - 1] >= '0') &&
                      (this.textBoxStepSize.Text[this.textBoxStepSize.Text.Length - 1] <= '9')) &&
                    (!(this.textBoxStepSize.Text[this.textBoxStepSize.Text.Length - 1] == '.')))
                {
                    this.textBoxStepSize.Text = text;
                }
            }
        }

        /// <summary>
        /// The text box 2_ text changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            string text = string.Empty;
            for (int i = 0; i < this.textBox2.Text.Length - 1; i++)
            {
                text += this.textBox2.Text[i];
            }

            if (this.textBox2.Text.Length >= 1)
            {
                if (
                    !((this.textBox2.Text[this.textBox2.Text.Length - 1] >= '0') &&
                      (this.textBox2.Text[this.textBox2.Text.Length - 1] <= '9')) &&
                    (!(this.textBox2.Text[this.textBox2.Text.Length - 1] == '.')))
                {
                    this.textBox2.Text = text;
                }
            }
        }

        /// <summary>
        /// The text box 3_ text changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            string text = string.Empty;
            for (int i = 0; i < this.textBox3.Text.Length - 1; i++)
            {
                text += this.textBox3.Text[i];
            }

            if (this.textBox3.Text.Length >= 1)
            {
                if (
                    !((this.textBox3.Text[this.textBox3.Text.Length - 1] >= '0') &&
                      (this.textBox3.Text[this.textBox3.Text.Length - 1] <= '9')) &&
                    (!(this.textBox3.Text[this.textBox3.Text.Length - 1] == '.')))
                {
                    this.textBox3.Text = text;
                }
            }
        }

        /// <summary>
        /// The button 11_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button11_Click(object sender, EventArgs e)
        {
            // Демонстрация построения сетки КЭ
            if (!this.timer2.Enabled)
            {
                this.button7.Enabled = false;
                this.button9.Enabled = false;
                this.buttonBuildFrontal.Enabled = false;
                this.buttonDelete.Enabled = false;
                this.buttonRegularization.Enabled = false;
                this.buttonSetStep.Enabled = false;
                this.button5.Enabled = false;
                this.button6.Enabled = false;
                this.buttonDelone.Enabled = false;
                this.hScrollBarSpeed.Enabled = false;
                this.checkBox1.Enabled = false;
                this.checkBox2.Enabled = false;
                this.checkBox3.Enabled = false;
                this.checkBox4.Enabled = false;

                this.buttonDemon.BackColor = this.AllocColor;

                this.bShowBedTriangle = false;
                this.button5.BackColor = this.BackAddDelColor;
                this.button6.BackColor = this.BackAddDelColor;
                this.bAdd = false;
                this.bDelete = false;
                this.bDrawMesh = true;
                this.DrawScale(true);
                this.DrawZonesZonepointsZonenum(true);
                this.DrawDensityFunction(true);
                this.timer2.Interval = this.iTimeDelay;
                this.iZone = 0;
                this.iPoint = 0;
                this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

                for (int i = 0; i < this.cZoneCount; i++)
                {
                    // Инициализация списка треугольников
                    this.InsidePoints[i] = new List<Point[]>();
                }

                this.ExternalFront = new Point[this.cZoneCount][];
                for (int i = 0; i < this.cZoneCount; i++)
                {
                    this.ExternalFront[i] = new Point[this.Front[i].Length];
                }

                for (int i = 0; i < this.cZoneCount; i++)
                {
                    for (int j = 0; j < this.Front[i].Length; j++)
                    {
                        this.ExternalFront[i][j] = this.Front[i][j];
                    }
                }

                this.timer2.Start();
            }
            else
            {
                this.buttonDemon.BackColor = this.BackAddDelColor;
                this.timer2.Stop();
                this.Mesh();
                this.DrawZonesZonepointsZonenum(true);
                this.DrawZonePointNum(this.bDrawZonePointNum);
                this.DrawZoneCoord(this.bDrawZoneCoord);
                this.DrawTriangleNum(this.bDrawTriangleNum);
                this.DrawDensityFunction(this.bDensityFunction);

                this.button7.Enabled = true;
                this.button9.Enabled = true;
                this.buttonBuildFrontal.Enabled = true;
                this.buttonDelete.Enabled = true;
                this.buttonRegularization.Enabled = true;
                this.buttonSetStep.Enabled = true;
                this.button5.Enabled = true;
                this.button6.Enabled = true;
                this.buttonDelone.Enabled = true;
                this.hScrollBarSpeed.Enabled = true;
                this.checkBox1.Enabled = true;
                this.checkBox2.Enabled = true;
                this.checkBox3.Enabled = true;
                this.checkBox4.Enabled = true;
            }
        }

        /// <summary>
        /// The timer 2_ tick.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void timer2_Tick(object sender, EventArgs e)
        {
            // Таймер демонстрационного построения сетки КЭ
            if (this.iPoint == 0)
            {
                this.FrontZone = new GraphicsPath();
                this.FrontZone.StartFigure();
                this.FrontZone.AddLines(this.Front[this.iZone]);
                this.FrontZone.CloseFigure();
                this.eee.DrawPath(this.ZonePen, this.FrontZone);
            }

            if (this.ExternalFront[this.iZone].Length > 3)
            {
                // Если длина фронта ещё может быть разбита
                double MinAngle, temp;
                int IndexMinAngle;
                MinAngle = this.FindAngle(0, this.iZone);
                IndexMinAngle = 0;
                for (int i = 1; i < this.ExternalFront[this.iZone].Length; i++)
                {
                    temp = this.FindAngle(i, this.iZone);
                    if (temp < MinAngle)
                    {
                        MinAngle = temp;
                        IndexMinAngle = i;
                    }
                }

                if ((MinAngle <= this.fMiterAngle) || (MinAngle == 90))
                {
                    int iLeftPoint = -1, iRightPoint = -1;
                    this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, this.iZone);
                    this.eee.DrawLine(
                        this.InsidePen, 
                        this.ExternalFront[this.iZone][iLeftPoint], 
                        this.ExternalFront[this.iZone][iRightPoint]);

                    var Triangle = new Point[3]; // Добавление треугольника к списку
                    Triangle[0] = this.ExternalFront[this.iZone][iLeftPoint];
                    Triangle[1] = this.ExternalFront[this.iZone][iRightPoint];
                    Triangle[2] = this.ExternalFront[this.iZone][IndexMinAngle];
                    this.InsidePoints[this.iZone].Add(Triangle);

                    this.DeletePoint(IndexMinAngle, this.iZone);
                }
                else
                {
                    int iLeftPoint = -1, iRightPoint = -1;
                    this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, this.iZone);
                    Point oldPoint = this.ExternalFront[this.iZone][IndexMinAngle];

                    Point newPoint = this.AddPoint(IndexMinAngle, MinAngle, this.iZone);
                    if ((newPoint.X > 0) && (newPoint.Y > 0))
                    {
                        this.eee.DrawLine(this.InsidePen, oldPoint, newPoint);
                        this.eee.DrawLine(this.InsidePen, newPoint, this.ExternalFront[this.iZone][iLeftPoint]);
                        this.eee.DrawLine(this.InsidePen, newPoint, this.ExternalFront[this.iZone][iRightPoint]);

                        Point[] Triangle1 = new Point[3], Triangle2 = new Point[3];
                            
                            // Добавление треугольников к списку
                        Triangle1[0] = this.ExternalFront[this.iZone][iLeftPoint];
                        Triangle1[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                        Triangle1[2] = newPoint;
                        this.InsidePoints[this.iZone].Add(Triangle1);
                        Triangle2[0] = this.ExternalFront[this.iZone][iRightPoint];
                        Triangle2[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                        Triangle2[2] = newPoint;
                        this.InsidePoints[this.iZone].Add(Triangle2);
                    }
                }
            }

            if (this.ExternalFront[this.iZone].Length == 3)
            {
                // Добавляем последний треугольник к списку треугольников
                var TriangleLast = new Point[3]; // Добавление треугольников к списку
                TriangleLast[0] = this.ExternalFront[this.iZone][0];
                TriangleLast[1] = this.ExternalFront[this.iZone][1];
                TriangleLast[2] = this.ExternalFront[this.iZone][2];
                this.InsidePoints[this.iZone].Add(TriangleLast);
                this.iZone++;
                this.iPoint = 0;

                if (this.iZone == this.cZoneCount)
                {
                    this.FillAllPoints();
                    this.DrawZonesZonepointsZonenum(true);
                    this.DrawZonePointNum(this.bDrawZonePointNum);
                    this.DrawZoneCoord(this.bDrawZoneCoord);
                    this.DrawTriangleNum(this.bDrawTriangleNum);
                    this.DrawDensityFunction(this.bDensityFunction);
                    this.button7.Enabled = true;
                    this.button9.Enabled = true;
                    this.buttonBuildFrontal.Enabled = true;
                    this.buttonDelete.Enabled = true;
                    this.buttonRegularization.Enabled = true;
                    this.buttonSetStep.Enabled = true;
                    this.button5.Enabled = true;
                    this.button6.Enabled = true;
                    this.buttonDelone.Enabled = true;
                    this.hScrollBarSpeed.Enabled = true;
                    this.checkBox1.Enabled = true;
                    this.checkBox2.Enabled = true;
                    this.checkBox3.Enabled = true;
                    this.checkBox4.Enabled = true;
                    this.timer2.Stop();
                }
            }
            else
            {
                this.iPoint++;
            }
        }

        /// <summary>
        /// The h scroll bar 1_ scroll.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
        {
            // Настройка задержки демонстрации
            this.iTimeDelay = this.hScrollBarSpeed.Value;
        }

        /// <summary>
        /// The button 12_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void button12_Click(object sender, EventArgs e)
        {
            // Задать функцию плотности
            if (!this.bDensityFunction)
            {
                this.buttonSetXY.BackColor = this.AllocColor;
                this.bDensityFunction = true;
                this.bShowDensityFunc = true;
            }
            else
            {
                this.textBoxFxy.Enabled = false;
                this.buttonSetXY.BackColor = this.BackAddDelColor;
                this.bDensityFunction = false;
            }
        }

        /// <summary>
        /// The text box 4_ leave.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox4_Leave(object sender, EventArgs e)
        {
            // Задание значения функции плотности
            if (this.textBoxFxy.Text != string.Empty)
            {
                this.DensityPoints[this.curZoneDensity].Add(this.curDensityFunc);
                if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) >= 20)
                {
                    this.textBoxFxy.Text = "20";
                }
                else if (Convert.ToSingle(this.textBoxFxy.Text, this.provider) < 0.1)
                {
                    this.textBoxFxy.Text = "0.1";
                }

                this.DensityValues[this.curZoneDensity].Add(
                    Math.Round(Convert.ToSingle(this.textBoxFxy.Text, this.provider), 2));
                this.DrawDensityFunction(true);
            }
        }

        /// <summary>
        /// The text box 4_ text changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void textBox4_TextChanged(object sender, EventArgs e)
        {
            ////string text = "";
            ////for (int i = 0; i < textBox4.Text.Length - 1; i++)
            ////    text += textBox4.Text[i];
            ////if (textBox4.Text.Length >= 1)
            ////    if (!((textBox4.Text[textBox4.Text.Length - 1] >= '0') && (textBox4.Text[textBox4.Text.Length - 1] <= '9')) && (!(textBox1.Text[textBox4.Text.Length - 1] == '.')))
            ////        textBox4.Text = text;
        }

        /// <summary>
        /// The picture box 1_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void pictureBox1_Click(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// The timer 3_ tick.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void timer3_Tick(object sender, EventArgs e)
        {
            if (this.iTimer3 < 2)
            {
                this.ImageDrawing();
                this.iTimer3++;
            }

            this.timer3.Stop();
            this.timer3.Enabled = false;
        }

        /// <summary>
        /// The form 1_ activated.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void Form1_Activated(object sender, EventArgs e)
        {
            this.iTimer3 = 0;
            this.timer3.Enabled = true;
            this.timer3.Start();
        }

        /// <summary>
        /// Найти ребра, которые принадлежат границе
        /// </summary>
        /// <returns>
        /// </returns>
        private List<Edge> EdgesOfFront()
        {
            var edgeListBeforeCleaning = new List<Edge>(40);
            var distinctNodes = new List<int>(30);
            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j <= this.cPointsInZone; j++)
                {
                    if (j == this.cPointsInZone)
                    {
                        var newEdge = new Edge(this.ZonesPointsNum[i][0], this.ZonesPointsNum[i][7]);
                        edgeListBeforeCleaning.Add(newEdge);

                        break;
                    }

                    if (j > 0)
                    {
                        var newEdge = new Edge(this.ZonesPointsNum[i][j - 1], this.ZonesPointsNum[i][j]);
                        edgeListBeforeCleaning.Add(newEdge);
                    }
                }
            }

            foreach (Edge edge in edgeListBeforeCleaning)
            {
                int countPoint1 = 0;
                int countPoint2 = 0;

                // считаем количество вхождений первой и второй точки ребра
                edgeListBeforeCleaning.ForEach(
                    nextEdge =>
                        {
                            {
                                if ((nextEdge.p1 == edge.p1) || (nextEdge.p2 == edge.p1))
                                {
                                    countPoint1++;
                                }

                                if ((nextEdge.p1 == edge.p2) || (nextEdge.p2 == edge.p2))
                                {
                                    countPoint2++;
                                }
                            }
                        });

                if (countPoint1 == 2)
                {
                    if (distinctNodes.Exists(node => node == edge.p1) == false)
                    {
                        distinctNodes.Add(edge.p1);
                    }
                }

                if (countPoint2 == 2)
                {
                    if (distinctNodes.Exists(node => node == edge.p2) == false)
                    {
                        distinctNodes.Add(edge.p2);
                    }
                }
            }

            var edgeListAfterCleaning = new List<Edge>(30);
            foreach (Edge edge in edgeListBeforeCleaning)
            {
                if (distinctNodes.Exists(node => (edge.p1 == node) || (edge.p2 == node)))
                {
                    edgeListAfterCleaning.Add(edge);
                }
            }

            return edgeListAfterCleaning;
        }

        /// <summary>
        /// The j delone test.
        /// </summary>
        private void JDeloneTest()
        {
            double epsilon = 1.0;
            int npts = 100; /* number of points to insert */
            int nedges = 10; /* number of edges to constrain */
            Mesh mesh;
            mesh = new Mesh(epsilon);
            float max, min;
            max = 400;
            min = 0;

            /* create a square boundary */
            var boundary = new BPoint[4];
            boundary[0] = new BPoint(min, min);
            boundary[1] = new BPoint(min, max);
            boundary[2] = new BPoint(max, max);
            boundary[3] = new BPoint(max, min);
            Java.Mesh.linkBoundary(boundary);
            mesh.init(boundary);
            var random = new Random(0);

            /* randomly insert interior points */
            for (int i = 0; i < npts; i++)
            {
                var p = new Java.Point();
                p.X = min + epsilon + random.Next() * (max - min - 2 * epsilon);
                p.Y = min + epsilon + random.Next() * (max - min - 2 * epsilon);
                mesh.addInteriorPoint(p);
            }

            /* randomly constrain edges */
            int s = mesh.size() - 1;
            for (int i = 0; i < nedges;)
            {
                Java.Point p1 = mesh.getPoint(random.Next() * s);
                Java.Point p2 = mesh.getPoint(random.Next() * s);
                if (p1 != p2)
                {
                    mesh.addConstraint(p1, p2);
                    i++;
                }
            }
        }

        /// <summary>
        /// The button delone_ click.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void buttonDelone_Click(object sender, EventArgs e)
        {
#if viewdebug
            timeStart.Reset();
            timeStart.Start();
#endif
            this.FindAllMeshNodesForDelone();

            List<Edge> edgeList = this.EdgesOfFront();
            var vertexList = new List<Triangulator.Geometry.Point>();
            for (int i = 0; i < this.Front.GetLength(0); i++)
            {
                for (int j = 0; j < this.Front[i].GetLength(0); j++)
                {
                    if (
                        vertexList.Exists(
                            vertex => ((vertex.X == this.Front[i][j].X) && (vertex.Y == this.Front[i][j].Y))) == false)
                    {
                        // int p = ZonesPointsNum[i][j];
                        int p = 0;
                        vertexList.Add(new Triangulator.Geometry.Point(this.Front[i][j].X, this.Front[i][j].Y, p));
                    }
                }
            }

            for (int i = 0; i < this.InsidePoints.GetLength(0); i++)
            {
                for (int j = 0; j < this.InsidePoints[i].Count; j++)
                {
                    for (int h = 0; h < 3; h++)
                    {
                        if (
                            vertexList.Exists(
                                vertex =>
                                ((vertex.X == this.InsidePoints[i][j][h].X) &&
                                 (vertex.Y == this.InsidePoints[i][j][h].Y))) == false)
                        {
                            // int p = ZonesPointsNum[i][j];
                            int p = 0;
                            vertexList.Add(
                                new Triangulator.Geometry.Point(
                                    this.InsidePoints[i][j][h].X, this.InsidePoints[i][j][h].Y, p));
                        }
                    }
                }
            }

            List<Triangle> triangeList = Delauney.Triangulate(vertexList);
            this.timeStart.Stop();

            var permitedTriangeList = new List<Triangle>();
            float xCentroid;
            float yCentroid;
            foreach (Triangle t in triangeList)
            {
                // координаты центра треугольника
                xCentroid = (float)(vertexList[t.p1].X + vertexList[t.p2].X + vertexList[t.p3].X) / 3;
                yCentroid = (float)(vertexList[t.p1].Y + vertexList[t.p2].Y + vertexList[t.p3].Y) / 3;
#if viewdebug
                eee.DrawLine(InsidePen, 0, yCentroid + 5, 1500, yCentroid + 5);
#endif

                // найти точки пересечения горизонтальной линии с границами пластины
                var intList = new SortedList<double, Triangulator.Geometry.Point>(50);

                // List<Triangulator.Geometry.Point> intersectionsList = new List<Triangulator.Geometry.Point>(5);
                for (int i = 0; i < this.ZonesPoints.GetLength(0); i++)
                {
                    for (int j = 0; j < this.ZonesPoints[i].GetLength(0); j++)
                    {
                        int pointNum1;
                        int pointNum2;

                        if (j > 0)
                        {
                            pointNum1 = j - 1;
                            pointNum2 = j;
                        }
                        else
                        {
                            pointNum1 = 0;
                            pointNum2 = 7;
                        }

                        if (
                            edgeList.Exists(
                                edge =>
                                ((edge.p1 == this.ZonesPointsNum[i][pointNum2]) ||
                                 (edge.p1 == this.ZonesPointsNum[i][pointNum1])) &&
                                ((edge.p2 == this.ZonesPointsNum[i][pointNum2]) ||
                                 (edge.p2 == this.ZonesPointsNum[i][pointNum1]))))
                        {
                            int x1 = this.ZonesPoints[i][pointNum1].X;
                            int y1 = this.ZonesPoints[i][pointNum1].Y;
                            int x2 = this.ZonesPoints[i][pointNum2].X;
                            int y2 = this.ZonesPoints[i][pointNum2].Y;
                            if ((Math.Abs(x1 - x2) < double.Epsilon) &&
                                (((yCentroid > y1) && (yCentroid < y2)) || ((yCentroid > y2) && (yCentroid < y1))))
                            {
                                intList.Add(
                                    x1, new Triangulator.Geometry.Point(x1, yCentroid, this.ZonesPointsNum[i][j]));
#if viewdebug
                                eee.DrawEllipse(InsidePen, x1, yCentroid, 5, 5);
#endif
                            }

                            if ((Math.Abs(x1 - x2) > double.Epsilon) &&
                                (((yCentroid > y1) && (yCentroid < y2)) || ((yCentroid > y2) && (yCentroid < y1))))
                            {
                                double k = 0;
                                double b = 0;
                                this.mathematic.FindLineEquation(new Point(x1, y1), new Point(x2, y2), ref k, ref b);
                                double checkingX = (yCentroid - b) / k;
                                intList.Add(
                                    checkingX, 
                                    new Triangulator.Geometry.Point(checkingX, yCentroid, this.ZonesPointsNum[i][j]));
#if viewdebug
                                eee.DrawEllipse(InsidePen, (float)checkingX, yCentroid, 5, 5);
#endif

                                // if(Math.Abs(checkingX -  
                            }
                        }
                    }
                }

                int position = 1;

                // узнаем на каком месте между точками пересечения с границей находится центровая точка             
                foreach (double xEdge in intList.Keys)
                {
                    if (xCentroid < xEdge)
                    {
                        break;
                    }

                    position++;
                }

                int ostatok = 0;
                Math.DivRem(position, 2, out ostatok);

                // если место нечетное то треугольник выходит за границы
                if (ostatok == 0)
                {
#if viewdebug
                    eee.DrawEllipse(InsidePen, xCentroid, yCentroid, 10, 10);
#endif
                    if (permitedTriangeList.Contains(t) == false)
                    {
                        permitedTriangeList.Add(t);
                        this.eee.DrawLine(
                            this.InsidePen, 
                            (float)vertexList[t.p1].X, 
                            (float)vertexList[t.p1].Y, 
                            (float)vertexList[t.p2].X, 
                            (float)vertexList[t.p2].Y);
                        this.eee.DrawLine(
                            this.InsidePen, 
                            (float)vertexList[t.p2].X, 
                            (float)vertexList[t.p2].Y, 
                            (float)vertexList[t.p3].X, 
                            (float)vertexList[t.p3].Y);
                        this.eee.DrawLine(
                            this.InsidePen, 
                            (float)vertexList[t.p1].X, 
                            (float)vertexList[t.p1].Y, 
                            (float)vertexList[t.p3].X, 
                            (float)vertexList[t.p3].Y);
                    }
                }
            }

#if viewdebug
            System.Windows.Forms.MessageBox.Show(string.Format("Time:{0}", timeStart.ElapsedMilliseconds));
#endif
            this.AllPointsArray = new List<Point>(vertexList.Count);
            int num = 1;
            foreach (Triangulator.Geometry.Point vert in vertexList)
            {
                this.AllPointsArray.Add(new Point((int)vert.X, (int)vert.Y));
                this.AllPointsNum.Add(num++);
            }

            foreach (Triangle tr in permitedTriangeList)
            {
                var pointsInTr = new Point[3];
                pointsInTr[0] = this.AllPointsArray[tr.p1];
                pointsInTr[1] = this.AllPointsArray[tr.p2];
                pointsInTr[2] = this.AllPointsArray[tr.p3];
                this.AllElem.Add(pointsInTr);
            }
        }

        /// <summary>
        /// Поиск вершин на плоскости как входных данных для делоне.
        /// </summary>
        private void FindAllMeshNodesForDelone()
        {
            this.InsidePoints = new List<Point[]>[this.cZoneCount]; // Массив координат всех треугольников

            // Инициализация списка треугольников
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.InsidePoints[i] = new List<Point[]>();
            }

            this.ExternalFront = new Point[this.cZoneCount][];
            for (int i = 0; i < this.cZoneCount; i++)
            {
                this.ExternalFront[i] = new Point[this.Front[i].Length];
            }

            for (int i = 0; i < this.cZoneCount; i++)
            {
                for (int j = 0; j < this.Front[i].Length; j++)
                {
                    this.ExternalFront[i][j] = this.Front[i][j];
                }
            }

            for (int j = 0; j < this.cZoneCount; j++)
            {
                // Выполняем цикл для каждой зоны
                while (this.ExternalFront[j].Length > 3)
                {
                    // Если длина фронта ещё может быть разбита
                    double MinAngle, temp;
                    int IndexMinAngle;
                    MinAngle = this.FindAngleChangedFromOriginal(0, j);
                    IndexMinAngle = 0;
                    for (int i = 1; i < this.ExternalFront[j].Length; i++)
                    {
                        temp = this.FindAngleChangedFromOriginal(i, j);
                        if (temp < MinAngle)
                        {
                            MinAngle = temp;
                            IndexMinAngle = i;
                        }
                    }

                    if ((MinAngle <= this.fMiterAngle) || ((MinAngle >= 89.99) && (MinAngle <= 90.01)))
                    {
                        int iLeftPoint = -1, iRightPoint = -1;
                        this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, j);

                        var Triangle = new Point[3]; // Добавление треугольника к списку
                        Triangle[0] = this.ExternalFront[j][iLeftPoint];
                        Triangle[1] = this.ExternalFront[j][iRightPoint];
                        Triangle[2] = this.ExternalFront[j][IndexMinAngle];
                        this.InsidePoints[j].Add(Triangle);

                        this.DeletePoint(IndexMinAngle, j);
                    }
                    else
                    {
                        int iLeftPoint = -1, iRightPoint = -1;
                        this.FindLeftRightIndex2(IndexMinAngle, ref iLeftPoint, ref iRightPoint, j);
                        Point oldPoint = this.ExternalFront[j][IndexMinAngle];

                        Point newPoint = this.AddPoint(IndexMinAngle, MinAngle, j);
                        if (this.bError)
                        {
                            return;
                        }

                        if ((newPoint.X > 0) && (newPoint.Y > 0))
                        {
                            Point[] Triangle1 = new Point[3], Triangle2 = new Point[3];
                                
                                // Добавление треугольников к списку
                            Triangle1[0] = this.ExternalFront[j][iLeftPoint];
                            Triangle1[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                            Triangle1[2] = newPoint;
                            this.InsidePoints[j].Add(Triangle1);
                            Triangle2[0] = this.ExternalFront[j][iRightPoint];
                            Triangle2[1] = oldPoint; // Формируем координаты треугольника для добавления к списку
                            Triangle2[2] = newPoint;
                            this.InsidePoints[j].Add(Triangle2);
                        }
                    }
                }

                // Добавляем последний треугольник к списку треугольников
                var TriangleLast = new Point[3]; // Добавление треугольников к списку
                TriangleLast[0] = this.ExternalFront[j][0];
                TriangleLast[1] = this.ExternalFront[j][1];
                TriangleLast[2] = this.ExternalFront[j][2];
                this.InsidePoints[j].Add(TriangleLast);
            }
        }

        #region Mesh analyzing

        /// <summary>
        /// The analyzing delone method.
        /// </summary>
        /// <param name="triangeList">
        /// The triange list.
        /// </param>
        /// <param name="vertexList">
        /// The vertex list.
        /// </param>
        private void AnalyzingDeloneMethod(List<Triangle> triangeList, List<Triangulator.Geometry.Point> vertexList)
        {
            long trianglesCount = 0;
            float maxSquare = -1;
            float minSquare = -1;
            long anglesCount = 0;
            double angleSum = 0;
            double minAngle = -1;
            bool minAngleWasSet = false;
            double maxAngle = -1;
            bool maxAngleWasSet = false;
            foreach (Triangle triangle in triangeList)
            {
                trianglesCount++;
                float square = 0;
                var point1 = new Point((int)vertexList[triangle.p1].X, (int)vertexList[triangle.p1].Y);
                var point2 = new Point((int)vertexList[triangle.p2].X, (int)vertexList[triangle.p2].Y);
                var point3 = new Point((int)vertexList[triangle.p3].X, (int)vertexList[triangle.p3].Y);

                double a = this.mathematic.FindDist(point1, point2);
                double b = this.mathematic.FindDist(point1, point3);
                double c = this.mathematic.FindDist(point3, point2);
                double angle1 = this.mathematic.CosineLaw(a, b, c);
                double angle2 = this.mathematic.CosineLaw(b, a, c);
                double angle3 = this.mathematic.CosineLaw(c, a, b);
                angleSum += angle1 + angle2 + angle3;
                anglesCount += 3;
                if (maxAngleWasSet == false)
                {
                    maxAngleWasSet = true;
                    maxAngle = angle1;
                }

                if (minAngleWasSet == false)
                {
                    minAngleWasSet = true;
                    minAngle = angle1;
                }

                if (minAngle > angle1)
                {
                    minAngle = angle1;
                }

                if (minAngle > angle2)
                {
                    minAngle = angle2;
                }

                if (minAngle > angle3)
                {
                    minAngle = angle3;
                }

                if (maxAngle < angle1)
                {
                    maxAngle = angle1;
                }

                if (maxAngle < angle2)
                {
                    maxAngle = angle2;
                }

                if (maxAngle < angle3)
                {
                    maxAngle = angle3;
                }

                // поиск минимальной и максимальной площади треугольника
                square = (float)this.mathematic.GeronLaw(point1, point2, point3, this.multiplier);
                if (maxSquare == -1)
                {
                    maxSquare = square;
                }

                if (minSquare == -1)
                {
                    minSquare = square;
                }

                if (square < minSquare)
                {
                    minSquare = square;
                }

                if (square > maxSquare)
                {
                    maxSquare = square;
                }
            }

            double midAngle = angleSum / anglesCount;

            MessageBox.Show(
                string.Format(
                    "Max square = {0}, Min square = {1}, Max angle = {2}, Min angle = {3}, Mid angle = {4},Tri count = {5}", 
                    maxSquare, 
                    minSquare, 
                    (int)maxAngle, 
                    (int)minAngle, 
                    (int)midAngle, 
                    trianglesCount));
        }

        /// <summary>
        /// The analyzing frontal method.
        /// </summary>
        private void AnalyzingFrontalMethod()
        {
            long trianglesCount = 0;
            float maxSquare = -1;
            float minSquare = -1;
            long anglesCount = 0;
            double angleSum = 0;
            double minAngle = -1;
            bool minAngleWasSet = false;
            double maxAngle = -1;
            bool maxAngleWasSet = false;
            {
                // for (int i = 0; i < cZoneCount; i++)
                foreach (var pointsList in this.InsidePoints)
                {
                    foreach (var points in pointsList)
                    {
                        trianglesCount++;
                        float square = 0;
                        Point point1 = points[0];
                        Point point2 = points[1];
                        Point point3 = points[2];

                        double a = this.mathematic.FindDist(point1, point2);
                        double b = this.mathematic.FindDist(point1, point3);
                        double c = this.mathematic.FindDist(point3, point2);
                        double angle1 = this.mathematic.CosineLaw(a, b, c);
                        double angle2 = this.mathematic.CosineLaw(b, a, c);
                        double angle3 = this.mathematic.CosineLaw(c, a, b);
                        angleSum += angle1 + angle2 + angle3;
                        anglesCount += 3;
                        if (maxAngleWasSet == false)
                        {
                            maxAngleWasSet = true;
                            maxAngle = angle1;
                        }

                        if (minAngleWasSet == false)
                        {
                            minAngleWasSet = true;
                            minAngle = angle1;
                        }

                        if (minAngle > angle1)
                        {
                            minAngle = angle1;
                        }

                        if (minAngle > angle2)
                        {
                            minAngle = angle2;
                        }

                        if (minAngle > angle3)
                        {
                            minAngle = angle3;
                        }

                        if (maxAngle < angle1)
                        {
                            maxAngle = angle1;
                        }

                        if (maxAngle < angle2)
                        {
                            maxAngle = angle2;
                        }

                        if (maxAngle < angle3)
                        {
                            maxAngle = angle3;
                        }

                        // square calc
                        square = (float)this.mathematic.GeronLaw(point1, point2, point3, this.multiplier);
                        if (maxSquare == -1)
                        {
                            maxSquare = square;
                        }

                        if (minSquare == -1)
                        {
                            minSquare = square;
                        }

                        if (square < minSquare)
                        {
                            minSquare = square;
                        }

                        if (square > maxSquare)
                        {
                            maxSquare = square;
                        }
                    }
                }
            }

            double midAngle = angleSum / anglesCount;

            MessageBox.Show(
                string.Format(
                    "Max square = {0}, Min square = {1}, Max angle = {2}, Min angle = {3}, Mid angle = {4},Tri count = {5}", 
                    maxSquare, 
                    minSquare, 
                    (int)maxAngle, 
                    (int)minAngle, 
                    (int)midAngle, 
                    trianglesCount));
        }

        #endregion
    }
}